diff --git a/Sources/CodexAccountSwitcher/main.swift b/Sources/CodexAccountSwitcher/main.swift index d41cc012..f2cac762 100644 --- a/Sources/CodexAccountSwitcher/main.swift +++ b/Sources/CodexAccountSwitcher/main.swift @@ -104,6 +104,7 @@ struct AccountUsage: Codable { var weeklyLimitUsedPercent: Int? var weeklyLimitWindowMins: Int? var weeklyLimitResetsAt: Date? + var rateLimitResetCreditsRemaining: Int? var lastRateLimitRefreshAt: Date? var rateLimitError: String? var authStaleAt: Date? @@ -120,6 +121,7 @@ struct LimitWindowSummary { struct RateLimitSummary { let daily: LimitWindowSummary? let weekly: LimitWindowSummary? + let resetCreditsRemaining: Int? } private struct AutomaticSwitchCandidate { @@ -598,6 +600,7 @@ final class CodexAccountSwitcher { usage.weeklyLimitUsedPercent = summary.weekly?.usedPercent usage.weeklyLimitWindowMins = summary.weekly?.windowDurationMins usage.weeklyLimitResetsAt = summary.weekly?.resetsAt + usage.rateLimitResetCreditsRemaining = summary.resetCreditsRemaining case .failure(let error): let message = Self.singleLine(error.localizedDescription, limit: 300) usage.rateLimitError = message @@ -1286,6 +1289,9 @@ final class CodexAccountSwitcher { try next.name.write(to: settings.activeAccountMarker, atomically: true, encoding: .utf8) recordSwitch(to: next.name, isAutomatic: isAutomatic) + if !isAutomatic { + clearPendingSwitch() + } let relaunch = relaunchCodexAppIfRunning() switch relaunch { case .relaunched: @@ -1746,7 +1752,10 @@ private final class CodexUsageAPIClient { throw CodexUsageAPIClientError.missingRateLimit } - return Self.summary(from: rateLimit) + return Self.summary( + from: rateLimit, + resetCreditsRemaining: response.rateLimitResetCredits?.availableCount + ) } private func readAccessToken() throws -> String { @@ -1794,7 +1803,7 @@ private final class CodexUsageAPIClient { return try result.get() } - private static func summary(from rateLimit: WhamRateLimit) -> RateLimitSummary { + private static func summary(from rateLimit: WhamRateLimit, resetCreditsRemaining: Int?) -> RateLimitSummary { let primary = rateLimit.primaryWindow.map(windowSummary) let secondary = rateLimit.secondaryWindow.map(windowSummary) @@ -1819,7 +1828,11 @@ private final class CodexUsageAPIClient { daily = nil } - return RateLimitSummary(daily: daily, weekly: weekly) + return RateLimitSummary( + daily: daily, + weekly: weekly, + resetCreditsRemaining: resetCreditsRemaining + ) } private static func windowSummary(_ window: WhamRateLimitWindow) -> LimitWindowSummary { @@ -1849,9 +1862,19 @@ private struct CodexAuthTokens: Decodable { private struct WhamUsageResponse: Decodable { let rateLimit: WhamRateLimit? + let rateLimitResetCredits: WhamRateLimitResetCredits? enum CodingKeys: String, CodingKey { case rateLimit = "rate_limit" + case rateLimitResetCredits = "rate_limit_reset_credits" + } +} + +private struct WhamRateLimitResetCredits: Decodable { + let availableCount: Int? + + enum CodingKeys: String, CodingKey { + case availableCount = "available_count" } } @@ -1970,7 +1993,8 @@ private final class CodexAppServerClient { return RateLimitSummary( daily: dailySource.map(windowSummary), - weekly: weeklySource.map(windowSummary) + weekly: weeklySource.map(windowSummary), + resetCreditsRemaining: response.rateLimitResetCredits?.availableCount ) } @@ -2247,6 +2271,11 @@ private struct JSONRPCErrorPayload: Decodable { private struct CodexRateLimitsResponse: Decodable { let rateLimits: CodexRateLimitSnapshot let rateLimitsByLimitId: [String: CodexRateLimitSnapshot]? + let rateLimitResetCredits: CodexRateLimitResetCredits? +} + +private struct CodexRateLimitResetCredits: Decodable { + let availableCount: Int? } private struct CodexRateLimitSnapshot: Decodable { diff --git a/docs/community/2026-07-18-community-research.md b/docs/community/2026-07-18-community-research.md new file mode 100644 index 00000000..180023a2 --- /dev/null +++ b/docs/community/2026-07-18-community-research.md @@ -0,0 +1,85 @@ +# Community Research and Approval Queue + +Initial research checked on 2026-07-18; the current `r/AI_Agents` and +`r/SideProject` threads were re-checked on 2026-07-19. Community rules change; +re-check each destination immediately before requesting approval to post. + +## Recommended initial queue + +| Priority | Community | Fit | Current constraints | Approval state | +| --- | --- | --- | --- | --- | +| 1 | r/GenAiApps | Direct fit for a generative-AI iPhone workflow | Self-promotion must be contextual and useful, use the appropriate flair, and avoid duplicate or unsafe links. | Maintainer approves the exact link-free post and `iOS` flair. Add a beta link only after separate verification and approval. | +| 2 | r/TestFlight | Direct access to beta testers | Link posts must point only to TestFlight; title should be the app name with at most a short message; use the app flair; keep comments on the beta; avoid repeat posts. | Hold until a public TestFlight link is tested, then maintainer approves the exact post. | +| 3 | r/BetaTests | Focused product-beta feedback | Posting identities must be at least 24 hours old with at least 2 combined karma. Posts should explain the product and ask specific feedback questions. | Maintainer approves the exact post and confirms identity eligibility. Keep it link-free until a direct beta URL is verified. | +| 4 | r/alphaandbetausers | Broad alpha/beta tester recruitment | No community-specific rules are visible, but recent moderation behavior and Reddit-wide authenticity rules still apply. | Maintainer approves the exact link-free post after a same-day rules and removals check. | +| 5 | r/AI_Agents | Coding-agent builders and users | Project promotion belongs in the weekly Project Display thread; links belong there rather than in standalone posts. Self-promotion should remain around one in ten contributions and must include useful context. | Hold until the identity has genuine non-promotional participation and the current thread is re-checked; then approve one no-link comment. | +| 6 | r/SideProject | Broad maker feedback | No community-specific About-page rules are visible. A current thread explicitly invites project sharing, but community discussion rejects promotion-only accounts and low-effort link dropping. | Prefer one approved no-link thread comment after genuine participation and a same-day thread/removal check. | +| 7 | r/ChatGPTCoding | AI coding users and agent-tool builders | Promotion belongs in the designated self-promotion thread; flair is required for main posts; promote a project only once in the thread's stated policy. Main-feed promotion requires moderator sponsorship through modmail. | Maintainer approval required. Use only the current self-promotion thread, not the main feed. | +| 8 | r/Codex | Best audience match for the Codex-focused beta | Content must be directly related to Codex, use the right flair, and avoid bots. The rules do not explicitly permit self-promotion. | Moderator approval and maintainer approval required before any promotional post. A human must post; do not automate. | +| 9 | r/iOSProgramming | Useful for a technical build retrospective | App promotion is allowed only on Saturday, limited to one app once per year, and requires genuine participation. Current automated moderation requires labeled Tech Stack, Development Challenge, and AI Disclosure sections. | Maintainer approval required after confirming account eligibility, Saturday timing, unused annual allowance, and all three required sections. | + +## Secondary or hold destinations + +| Community | Assessment | Decision | +| --- | --- | --- | +| r/MacApps | Relevant to the menu-bar app, but the community requires 10 local karma and limits promotion to once per developer in 30 days. Main-feed promotion also requires an established trust signal or a public transparency path; other promotions belong in the monthly App Pile megathread. | Hold for the App Pile only. A maintainer must verify local-karma eligibility, the current megathread, and its required format. Never manufacture karma or expose a private identity to qualify. | +| r/OpenAI | Relevant but broad. Self-promotion should remain under 10% of participation, must be a contextual text post rather than a direct-link post, and participation is expected before advertising. | Hold until the identity has genuine participation and a maintainer approves a contextual post. | +| Show HN | A project must be personally built, directly usable, non-trivial, and ready for the author to discuss. Show HN discourages signup barriers and vote coordination. | Hold until the public beta is immediately testable and a maintainer can be present to answer questions. | +| r/SwiftUI | Promotion is allowed only when source code is provided and the app is open source. CodePilot is source-available under a noncommercial license, not OSI open source. | Do not promote CodePilot there under the current rules. | +| r/iOSApps | Requires 10 local karma, disclosure, ABC-format promotion, official App Store/TestFlight links, and either qualification or the monthly App Shelf megathread. More importantly, its current rules exclude generative-AI and AI-wrapped apps when AI is a core feature. | Do not promote CodePilot there under the current rules. Use r/TestFlight instead. | + +## Rule sources + +- [r/GenAiApps rules](https://www.reddit.com/r/GenAiApps/about/rules) +- [r/TestFlight rules](https://www.reddit.com/r/TestFlight/about/rules) +- [r/BetaTests rules](https://www.reddit.com/r/BetaTests/about/rules) +- [r/BetaTests posting guidance](https://www.reddit.com/r/BetaTests/comments/1ufs2a9/community_rules/) +- [r/alphaandbetausers rules](https://www.reddit.com/r/alphaandbetausers/about/rules) +- [r/AI_Agents rules](https://www.reddit.com/r/AI_Agents/about/) +- [r/AI_Agents current Project Display thread](https://www.reddit.com/r/AI_Agents/comments/1ukprfr/weekly_thread_project_display/) +- [r/SideProject current self-promotion thread](https://www.reddit.com/r/SideProject/comments/1utus1n/whats_everyone_working_on_lets_self_promote/) +- [r/ChatGPTCoding rules](https://www.reddit.com/r/ChatGPTCoding/about/rules) +- [r/ChatGPTCoding promotion thread example](https://www.reddit.com/r/ChatGPTCoding/comments/1ryqth6/self_promotion_thread/) +- [r/Codex rules](https://www.reddit.com/r/codex/about/rules) +- [r/iOSProgramming rules](https://www.reddit.com/r/iOSProgramming/about/rules) +- [r/iOSProgramming App Saturday format update](https://www.reddit.com/r/iOSProgramming/comments/1pnivdy/proposed_update_to_app_saturday_feedback_requested/) +- [r/iOSProgramming current missing-section enforcement example](https://www.reddit.com/r/iOSProgramming/comments/1utie4g/removed/) +- [r/MacApps rules](https://www.reddit.com/r/macapps/about/rules) +- [r/MacApps trust and transparency update](https://www.reddit.com/r/macapps/comments/1ryaeex/rmacapps_mods_went_too_far_whats_changing_phase_3/) +- [r/OpenAI rules](https://www.reddit.com/r/OpenAI/about/rules) +- [r/SideProject rules](https://www.reddit.com/r/SideProject/about/rules) +- [r/SwiftUI rules](https://www.reddit.com/r/SwiftUI/about/rules) +- [r/iOSApps rules](https://www.reddit.com/r/iosapps/about/rules) +- [Show HN guidelines](https://news.ycombinator.com/showhn.html) + +## Required approvals + +- Every public post or comment requires final maintainer approval under the + CodePilot launch policy. +- r/GenAiApps requires approval of the exact text and `iOS` flair. Any later + beta link requires separate verification and approval. +- r/BetaTests requires confirmation that the identity is at least 24 hours old + and has at least 2 combined karma; do not create or manufacture activity to + qualify. +- r/alphaandbetausers requires a same-day check of its live rules and recent + removals because it publishes no community-specific rules. +- r/AI_Agents requires genuine non-promotional participation, a safely + compliant one-in-ten ratio, and a same-day check of the weekly Project + Display thread. Do not use a standalone project post. +- r/SideProject requires genuine participation and a same-day check of the + current self-promotion thread and recent removals. Use the no-link thread + comment rather than a standalone launch post. +- r/Codex requires moderator confirmation because its published rules do not + explicitly authorize project promotion. +- r/iOSProgramming requires confirmation of Saturday timing, current account + eligibility, genuine prior activity, the once-per-year allowance, and the + required Tech Stack, Development Challenge, and AI Disclosure sections. +- r/MacApps requires confirmation of 10 local karma, the current App Pile + megathread, the 30-day allowance, and the required post format. The + `codepilotios` identity must not disclose private identity details to qualify + for a main-feed transparency path. +- r/OpenAI requires genuine prior participation before self-promotion. +- r/iOSApps is excluded from the posting queue while its no-AI rule remains. + +The broader research archive, including held and excluded destinations, is in +[`ops/agents/community-drafts/2026-07-01-codepilot-beta-drafts.md`](../../ops/agents/community-drafts/2026-07-01-codepilot-beta-drafts.md). diff --git a/docs/community/2026-07-18-draft-posts-and-comments.md b/docs/community/2026-07-18-draft-posts-and-comments.md new file mode 100644 index 00000000..a6573a54 --- /dev/null +++ b/docs/community/2026-07-18-draft-posts-and-comments.md @@ -0,0 +1,391 @@ +# Beta-Focused Draft Posts and Comments + +All copy below is unposted. Bracketed values must be replaced and verified during +final approval. Every draft uses the public `codepilotios` identity. + +## r/GenAiApps + +**Status:** Preferred first placement. Use the `iOS` flair and keep the post +link-free until a public beta URL is separately verified and approved. + +**Title** + +> I built an iPhone companion for Codex sessions running on your Mac — looking for beta workflow feedback + +**Body** + +> Disclosure: we build CodePilot; this is the project's account. +> +> CodePilot is a beta Mac + iPhone companion for people who already run Codex on +> a Mac they control. +> +> The idea is to leave the coding-agent session, credentials, and project files +> on the Mac while giving the iPhone a focused view of session status, threads, +> file uploads, notifications, and controls to steer or stop an active turn. The +> Mac runs a token-protected local gateway; remote access in the current beta +> uses a Cloudflare Tunnel controlled by the tester. +> +> We are trying to learn whether this solves a real generative-AI workflow +> problem or just moves a terminal-shaped problem onto a smaller screen. The +> feedback that would help most is: +> +> - when you would actually check or control a coding-agent session from your phone; +> - which remote actions feel useful versus risky; +> - whether the Mac gateway and iPhone connection model is understandable; and +> - what trust or setup concern would stop you from trying the beta. +> +> This is a feedback request, not an upvote request. Please do not share +> credentials, gateway tokens, private hostnames, private logs, screenshots, or +> project files. We will add an approved beta link only when public distribution +> is ready. + +## r/BetaTests + +**Status:** Use only after a maintainer confirms the identity is at least 24 +hours old with at least 2 combined karma. Keep the post link-free until a direct +public beta URL is verified and approved. + +**Title** + +> Looking for setup feedback on CodePilot, an iPhone companion for Codex sessions on a Mac + +**Body** + +> Disclosure: we build CodePilot; this is the project's account. +> +> We are looking for a small number of beta testers who already run Codex on +> macOS and can give specific setup feedback. +> +> CodePilot leaves the Codex session, credentials, and project files on the Mac. +> A token-protected local gateway gives the iPhone companion narrow access to +> session status, threads, file uploads, notifications, and controls to steer or +> stop an active turn. For the current public-beta remote path, the tester +> connects through a Cloudflare Tunnel they control. +> +> The beta questions we most need answered are: +> +> - Is the Mac gateway and iPhone pairing flow understandable without live help? +> - Is it clear what the gateway token protects and how to recover from a rejected token? +> - Does checking or steering a coding-agent turn from a phone solve a real workflow problem? +> - Which trust or setup concern would make you stop testing? +> +> This is a feedback request, not an upvote request. Please do not share +> credentials, gateway tokens, private hostnames, private logs, screenshots +> containing private project data, or project files in replies. + +## r/alphaandbetausers + +**Status:** Use only after a same-day review of the live rules and recent +removals. Do not promise reciprocal testing or incentives. Keep the post +link-free until a direct public beta URL is verified and approved. + +**Title** + +> Looking for Mac-based Codex users to test an iPhone companion setup + +**Body** + +> Disclosure: we build CodePilot; this is the project's account. +> +> We are looking for a small number of beta testers who already run Codex on +> macOS and can give specific feedback on a Mac-to-iPhone setup. +> +> CodePilot keeps the Codex session, credentials, and project files on the Mac. +> A token-protected local gateway gives the iPhone companion narrow access to +> session status, threads, file uploads, notifications, and controls to steer or +> stop an active turn. For remote access in the current beta, testers use a +> Cloudflare Tunnel they control. +> +> The questions we most need answered are: +> +> - Can you complete the Mac gateway and iPhone connection flow without live help? +> - Is it clear what the gateway token protects and how to recover from a rejected connection? +> - Does checking or steering a coding-agent turn from a phone solve a real workflow problem? +> - Which setup or trust concern would make you stop testing? +> +> This is a feedback request, not an upvote request. Please do not share +> credentials, gateway tokens, private hostnames, private logs, screenshots +> containing private project data, or project files in replies. + +## r/TestFlight + +**Status:** Preferred first post after `[TESTFLIGHT_URL]` is publicly reachable. + +**Title** + +> CodePilot — iPhone companion for Codex CLI + +**Link target** + +> [TESTFLIGHT_URL] + +**First comment** + +> Disclosure: this is the CodePilot project account, and we build the app. +> +> CodePilot is a public beta for people who already run Codex CLI on a Mac and +> want to check threads, usage status, and account state from an iPhone. The beta +> also supports file uploads, turn controls where available, and turn-finished +> notifications through a gateway running on your own Mac. +> +> The current setup uses a user-controlled Cloudflare Tunnel for iPhone access. +> It is still a beta, so please use a trusted Mac and read the security and privacy +> notes before exposing the gateway. +> +> The feedback that would help most: +> +> - Where did setup become unclear? +> - Did the first iPhone connection work without recovery steps? +> - Which thread or turn control felt unreliable? +> +> Please do not share gateway URLs, tokens, account names, private screenshots, +> or unsanitized logs in public replies. Use the feedback channel included with +> the beta for anything that should not be shared in the thread. + +## r/ChatGPTCoding self-promotion thread + +**Status:** Use only as one comment in the currently visible designated +promotion thread after a same-day check that it remains open and that the +identity can participate without an account-karma removal or manual-review +hold. Do not use this copy as a main-feed post. + +> Disclosure: we build CodePilot; this is its project account. +> +> We are preparing a public beta of an iPhone companion for people who already +> use Codex CLI on a Mac. CodePilot keeps the coding-agent process and credentials +> on the user's Mac, then exposes threads, usage status, file uploads, turn +> controls, and notifications to the iPhone app through a local gateway. +> +> We are looking for feedback on setup clarity and connection reliability, not a +> polished-launch verdict. If that workflow matches how you use coding agents, +> the beta is here: [TESTFLIGHT_URL] +> +> Technical details and beta limitations: [PUBLIC_REPOSITORY_URL] +> +> Please keep tokens, hostnames, account names, private screenshots, and raw logs +> out of public feedback. + +## r/Codex moderator approval request + +**Status:** Draft modmail only. A maintainer must approve sending it, and a human +must send it. Do not automate. + +**Subject** + +> Permission to share a transparent CodePilot TestFlight beta post? + +**Body** + +> Hello moderators, +> +> We maintain CodePilot, a Mac menu-bar app, local gateway, and iPhone companion +> for existing Codex CLI users. We would like to ask before sharing a single, +> clearly disclosed beta post requesting feedback on setup and reliability. +> +> The post would link to the public TestFlight beta and public source-available +> repository, make no pricing claims, and explicitly warn testers not to share +> credentials, gateway URLs, private screenshots, or unsanitized logs. We would +> use the CodePilot project identity and would not automate the post or repeat it. +> +> Is that appropriate for r/Codex? If so, which flair and format should we use? + +### r/Codex post, only if moderators approve + +**Title** + +> We built an iPhone companion for Codex CLI and are looking for beta setup feedback + +**Body** + +> Disclosure: we build CodePilot; this is the project's account. +> +> CodePilot is a Mac menu-bar app, local gateway, and iPhone companion for people +> who already run Codex CLI on a Mac. The current beta lets you inspect threads +> and usage status, upload files, steer or stop turns where supported, and receive +> turn-finished notifications from an iPhone. +> +> It does not replace Codex CLI. The coding-agent process and credentials remain +> on the Mac. Remote access currently uses a user-controlled Cloudflare Tunnel, +> so this is for testers who are comfortable reviewing the setup and security +> notes. +> +> We would especially value feedback on three things: +> +> 1. Can you connect the iPhone within five minutes after Mac setup? +> 2. Are connection and authentication failures actionable? +> 3. Which remote control feels least dependable? +> +> TestFlight: [TESTFLIGHT_URL] +> +> Technical details and known beta limits: [PUBLIC_REPOSITORY_URL] +> +> Please do not post gateway URLs, tokens, account names, private screenshots, or +> unsanitized logs. We will be here to answer technical questions and collect +> reproducible feedback. + +## r/iOSProgramming App Saturday + +**Status:** Use only on Saturday after confirming genuine prior participation, +current account eligibility, and that the account has not used the once-per-year +app allowance. Keep all three labeled sections below; current automated +moderation removes App Saturday posts that omit any of them. + +**Title** + +> Building an iPhone control surface for a coding agent running on a Mac + +**Body** + +> Disclosure: we build CodePilot; this is the project's account. +> +> **Tech Stack** +> +> The iPhone app is built with SwiftUI. It talks to a token-protected local +> gateway running on the user's Mac. A Mac menu-bar app surfaces local Codex +> account and usage state. For remote access in the current beta, the iPhone +> reaches the gateway through a user-controlled Cloudflare Tunnel and still +> authenticates with a bearer token. +> +> The client focuses on connection setup, gateway health, thread and session +> status, file uploads, usage and account state, notifications, and supported +> controls for steering or stopping active turns. +> +> **Development Challenge** +> +> The hard part was making remote control useful without pretending the phone +> owns the coding-agent session. The source of truth still lives on the Mac: +> credentials, project files, active turns, and account state. The UI also has +> to distinguish a tunnel failure, an unreachable gateway, and rejected +> authentication instead of collapsing them into one generic connection error. +> +> We kept the iPhone app as a narrow gateway client and modeled each setup +> failure as a recoverable connection state. We are now testing whether someone +> who did not build the system can understand what stays local, what is remote, +> what the token protects, and which recovery action to take. +> +> **AI Disclosure** +> +> AI-assisted. Coding agents have assisted with parts of the planning, copy, and +> implementation. Security-sensitive flows, gateway exposure, authentication, +> and release materials remain subject to human review. +> +> We would value feedback from iOS and macOS developers on whether this +> architecture and its connection states are understandable. It is an early +> beta; please do not put tokens, hostnames, account names, private screenshots, +> or unsanitized logs in public feedback. + +## r/MacApps App Pile megathread + +**Status:** Hold until the account has 10 genuine local karma, the 30-day +allowance is unused, and a maintainer has verified the current App Pile thread +and required format. Do not disclose a private identity to qualify for the main +feed. + +> Disclosure: we build CodePilot; this is the project's account. +> +> **Answer:** CodePilot is a Mac menu-bar app and iPhone companion for people who +> already run Codex CLI on a Mac and want to check or control a session while +> away from the computer. +> +> **Better:** The coding-agent process and credentials stay on the user's Mac. +> The app adds saved account profiles, usage status, a local gateway, iPhone +> thread visibility, file uploads, supported turn controls, and notifications. +> The public beta is aimed at technical testers who are comfortable reviewing +> its setup, privacy, and security documentation. +> +> **Cost:** This draft is for beta testing only; no future pricing details are +> being announced. Project and build instructions: [PUBLIC_REPOSITORY_URL] +> TestFlight companion: [TESTFLIGHT_URL] + +## r/AI_Agents weekly Project Display thread + +**Status:** Hold until the `codepilotios` identity has genuine non-promotional +participation and remains safely below the community's one-in-ten +self-promotion guideline. A maintainer must confirm the current weekly thread +is open and approve this exact no-link comment before a human posts it. + +> Disclosure: we build CodePilot; this is the project's account. +> +> CodePilot is a beta Mac + iPhone companion for people who run Codex sessions +> on a Mac they control. +> +> The agent-workflow question we are exploring is what should remain possible +> after you leave the terminal. CodePilot keeps the Codex session, credentials, +> and project files on the Mac. A token-protected local gateway gives the iPhone +> client narrow access to session status, threads, file uploads, notifications, +> and controls to steer or stop an active turn. The current remote path uses a +> Cloudflare Tunnel controlled by the tester. +> +> We would value feedback from people who run coding agents on longer tasks: +> +> - Which remote actions are genuinely useful: status, steering, stopping, file upload, or none of them? +> - Which actions should always require a fresh confirmation on the Mac or phone? +> - Does a user-owned gateway and tunnel clarify the trust boundary, or just make setup harder? +> - What audit or recovery information would you expect before connecting a phone to an active agent session? +> +> This is a workflow and trust feedback request, not an upvote request. We have +> left out the beta link until public distribution is approved. Please do not +> share credentials, gateway tokens, private hostnames, logs, screenshots, or +> project files in replies. + +## r/SideProject self-promotion thread + +**Status:** Optional later comment. Use only after genuine participation and a +same-day check that the current thread still explicitly invites project +sharing. Keep it link-free and do not publish it alongside focused beta posts. + +> Disclosure: we build CodePilot; this is the project's account. +> +> We are preparing CodePilot, a beta Mac + iPhone companion for people who run +> Codex sessions on a Mac they control. +> +> We built it around a specific problem: a coding-agent turn can keep running +> after you leave your desk, but we do not want to move provider credentials or +> project files to another hosted service. CodePilot leaves those on the Mac. A +> token-protected local gateway gives the iPhone client narrow access to session +> status, threads, file uploads, notifications, and controls to steer or stop an +> active turn. The current remote path uses a Cloudflare Tunnel controlled by +> the tester. +> +> We are looking for blunt feedback on the idea before broader distribution: +> +> - Is checking or steering a coding-agent session from a phone a real workflow, or just a smaller terminal-shaped distraction? +> - Does the Mac gateway plus user-owned tunnel model feel understandable? +> - Which part would stop you from trying the beta: setup effort, token handling, remote access, or something else? +> +> This is a feedback request, not an upvote request. We have left out the beta +> link until public distribution is approved. Please do not share credentials, +> gateway tokens, private hostnames, logs, screenshots, or project files in +> replies. + +## Show HN + +**Status:** Hold until a maintainer confirms the beta is directly usable and can +remain present to answer questions. + +**Title** + +> Show HN: CodePilot – control Codex CLI sessions from an iPhone + +**Submission URL** + +> [PUBLIC_REPOSITORY_URL] + +**Opening comment** + +> We built CodePilot because Codex CLI sessions often keep running on a Mac while +> the person using them steps away. It is a Mac menu-bar app, local Python gateway, +> and Swift iPhone client for inspecting threads and usage, uploading files, +> steering or stopping turns where supported, and receiving completion +> notifications. +> +> The core design constraint is that Codex and its credentials remain on the Mac. +> The current remote path uses a user-controlled Cloudflare Tunnel. That makes the +> architecture inspectable, but setup and failure recovery are still rough enough +> that we are calling this a beta. +> +> The repository includes build instructions, architecture, security notes, and +> current limitations. We would value feedback on whether the trust boundary is +> understandable and whether the setup diagnostics are specific enough. +> +> Disclosure: this is the CodePilot project account, and we built it. diff --git a/docs/community/2026-07-19-community-checkpoint.md b/docs/community/2026-07-19-community-checkpoint.md new file mode 100644 index 00000000..9dcdb559 --- /dev/null +++ b/docs/community/2026-07-19-community-checkpoint.md @@ -0,0 +1,113 @@ +# Community Drafts Checkpoint — 2026-07-19 + +This is a research and approval checkpoint for the CodePilot public beta. No +account was created, and no post, comment, profile change, modmail, or other +public action was made. + +All proposed activity uses the public `codepilotios` identity, discloses the +maker relationship, asks for beta workflow or setup feedback, and makes no paid +subscription claim. + +## Communities researched + +The live Reddit rules were re-checked for the destinations most likely to affect +the first beta placements. The broader community survey remains in +[the July 18 research queue](2026-07-18-community-research.md). + +| Community | Current fit | Result for this beta queue | +| --- | --- | --- | +| `r/GenAiApps` | Strong | Preferred first placement. Valuable, contextual self-promotion is allowed; use an appropriate flair, avoid duplicate or low-effort promotion, and keep the first draft link-free. | +| `r/TestFlight` | Strong after distribution is ready | Hold until a direct public Apple TestFlight URL is verified and approved. New posts may contain only the TestFlight link, need the app flair, and should use the app name with no recruitment tag in the title. Put later updates in comments rather than reposting. | +| `r/BetaTests` | Strong for focused tester feedback | Use the prepared no-link draft only after a maintainer verifies the identity's age and karma eligibility and re-checks the posting guidance. | +| `r/alphaandbetausers` | Good secondary tester pool | Its rules endpoint currently publishes no community-specific rules. Use only after a same-day review of rules and recent removals; do not offer incentives or reciprocal testing. | +| `r/AI_Agents` | Good agent-workflow feedback pool, participation-gated | Project promotion belongs in the current weekly Project Display thread. The community permits limited self-promotion at roughly one in ten contributions, requires substantive context, and routes project links to that thread. Use the prepared no-link comment only after genuine non-promotional participation and a same-day thread check. | +| `r/SideProject` | Broad secondary feedback pool | Its About page still publishes no community-specific rules, and a current thread explicitly invites projects and feedback. Prefer one prepared no-link comment in that thread over a standalone post, and use only after genuine participation plus a same-day thread and removal check. | +| `r/ChatGPTCoding` | Good audience, gated placement | Maker-authored service promotion belongs in the designated self-promotion thread. The currently visible thread still receives comments, but its automated moderation actively removes or holds comments based on account karma. Main-feed placement requires moderator sponsorship. Confirm thread status and identity eligibility before a human posts one approved comment. | +| `r/Codex` | Best topical match, moderator-first | Posts must be directly about Codex, use the right flair, and must not use bots. The published rules do not explicitly authorize maker promotion, so send the prepared permission request manually and post only if moderators and a maintainer approve. | +| `r/iOSProgramming` | Good technical retrospective, not recruitment-first | App promotion is limited to Saturday and one app per year. Current enforcement requires labeled Tech Stack, Development Challenge, and AI Disclosure sections. Use the revised technical draft only after account eligibility, timing, and the annual allowance are confirmed. | +| `r/MacApps` | Relevant but currently held | Requires 10 local karma, official distribution links, relationship disclosure, no more than one developer promotion in 30 days, and either main-feed qualification or the current promotion megathread. Do not manufacture eligibility or disclose a private identity. | +| `r/OpenAI` | Broad, participation-gated | Direct self-promotional project-link posts are not allowed; contextual text posts should stay under the one-in-ten guideline and follow genuine participation. Hold for a later moderator-approved discussion. | +| `r/SwiftUI` | Not eligible for this campaign | App promotion requires source code and describes eligible projects as open source. CodePilot is source-available under a noncommercial license, not OSI open source. Do not promote it there. | +| `r/iOSApps` | Not eligible for this campaign | Current rules prohibit generative-AI and AI-wrapped apps and direct them to `r/GenAiApps`. Do not use either the main feed or its promotion megathread for CodePilot. | + +## Drafts prepared + +The approval-ready draft library is in +[Beta-Focused Draft Posts and Comments](2026-07-18-draft-posts-and-comments.md). +It contains: + +- a link-free `r/GenAiApps` feedback post; +- no-link tester requests tailored to `r/BetaTests` and + `r/alphaandbetausers`; +- a TestFlight-only link post and safety-focused first comment with no + additional URL; +- a single `r/ChatGPTCoding` self-promotion-thread comment; +- no-link thread comments for `r/AI_Agents` and `r/SideProject`, each held + behind its participation and same-day thread checks; +- an `r/Codex` moderator permission request and conditional post; +- a technical `r/iOSProgramming` App Saturday post; +- held drafts for later communities, each with its eligibility gate; and +- transparent profile and reusable response copy in + [the profile and response library](profile-and-response-library.md). + +Bracketed URLs remain intentionally unresolved. They must not be replaced until +the exact public TestFlight or repository URL is reachable, privacy-audited, and +approved. + +## Rules and actions requiring approval + +Every public post or comment needs final maintainer approval under the launch +plan. The following destinations add a community-specific gate: + +- `r/TestFlight`: approve and verify the direct Apple TestFlight URL, exact + title, and app flair. +- `r/BetaTests`: confirm account age and karma eligibility. +- `r/alphaandbetausers`: perform a same-day rules and recent-removals check. +- `r/AI_Agents`: confirm genuine non-promotional participation, a safely + compliant one-in-ten ratio, and that the current weekly Project Display + thread remains open. Any later approved link belongs in the thread comment, + not a standalone project post. +- `r/SideProject`: confirm genuine participation and that the current + self-promotion thread remains open; use the approved no-link comment only, + not a standalone launch post. +- `r/ChatGPTCoding`: confirm the designated thread is still open and the + identity can participate without an account-karma removal or manual-review + hold; main-feed placement additionally requires moderator sponsorship. +- `r/Codex`: moderator permission, correct flair, maintainer approval, and a + human-authored manual post with no automation. +- `r/iOSProgramming`: Saturday timing, current account eligibility, genuine + prior participation, an unused once-per-year app allowance, and the required + Tech Stack, Development Challenge, and AI Disclosure sections. +- `r/MacApps`: 10 genuine local karma, official distribution, the current + promotion format, and the 30-day allowance. +- `r/OpenAI`: genuine prior participation and a compliant one-in-ten ratio; + moderator confirmation is recommended before mentioning CodePilot. + +The concise maintainer action list remains in +[`ops/agents/escalations/community-drafts.md`](../../ops/agents/escalations/community-drafts.md). + +## Live rule sources + +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- +- + +Re-read the target's rules, pinned posts, and active promotion thread immediately +before any approved manual submission because community rules and moderation +formats can change without notice. diff --git a/docs/community/README.md b/docs/community/README.md new file mode 100644 index 00000000..a33b8486 --- /dev/null +++ b/docs/community/README.md @@ -0,0 +1,31 @@ +# CodePilot Community Drafts + +These files are an approval-gated community launch kit for the CodePilot public +beta. They are drafts only. Do not create accounts, post, comment, send modmail, +or reuse the copy as an advertisement without a maintainer reviewing the target +community's current rules. + +Use the public `codepilotios` identity and disclose the relationship to CodePilot +in every post or comment that mentions the project. + +## Draft files + +- [Current research checkpoint (2026-07-19)](2026-07-19-community-checkpoint.md) +- [Research and posting queue](2026-07-18-community-research.md) +- [Tailored posts and comments](2026-07-18-draft-posts-and-comments.md) +- [Profile and reusable replies](profile-and-response-library.md) +- [Comprehensive research and held-draft archive](../../ops/agents/community-drafts/2026-07-01-codepilot-beta-drafts.md) + +## Before any approved post + +1. Re-read the live community rules and pinned posts on the day of posting. +2. Confirm that the `codepilotios` account meets community-age, karma, and + participation requirements without manufacturing engagement. +3. Replace bracketed placeholders with public, tested URLs only. +4. Confirm that the current TestFlight build and public documentation match every + product claim. +5. Remove any screenshot, log, hostname, token, account name, or local path that + has not passed the privacy audit. +6. Obtain explicit maintainer approval for the final post and destination. +7. Post once. Do not coordinate votes, repeat the same promotion across threads, + or use automated posting. diff --git a/docs/community/profile-and-response-library.md b/docs/community/profile-and-response-library.md new file mode 100644 index 00000000..c9ba74b7 --- /dev/null +++ b/docs/community/profile-and-response-library.md @@ -0,0 +1,86 @@ +# Public Profile and Response Library + +These are drafts for the `codepilotios` identity. Do not create or modify an +account, profile, post, or comment without explicit maintainer approval. + +## Profile bio + +> Official project account for CodePilot, a Mac and iPhone companion for Codex +> CLI. Sharing transparent public-beta updates and collecting technical feedback. +> Built by the CodePilot maintainers. + +## Short disclosure + +> Disclosure: we build CodePilot; this is the project's account. + +Use the disclosure in every post or comment that mentions or links CodePilot, +even when someone else asks for a recommendation. + +## Reusable replies + +### What does it replace? + +> It does not replace Codex CLI. Codex continues to run on your Mac. CodePilot adds +> a menu-bar app, a local gateway, and an iPhone client for remote visibility and +> controls. Disclosure: we build CodePilot. + +### Where do credentials go? + +> The current beta does not require a hosted CodePilot service. Codex credentials +> remain on the Mac. The iPhone authenticates to the user's gateway. Remote testers +> should review the security notes before exposing that gateway. Disclosure: we +> build CodePilot. + +### Why does the beta use Cloudflare Tunnel? + +> The Mac gateway listens on local loopback by default. The current public-beta +> setup uses a tunnel controlled by the tester so the iPhone can reach it without +> opening an inbound port. It adds setup complexity, which is one of the areas we +> are actively testing. Disclosure: we build CodePilot. + +### Is it open source? + +> It is source-available for noncommercial use, but it is not OSI open source +> because commercial use is restricted. The repository includes the exact license +> terms. Disclosure: we build CodePilot. + +### Does it support other coding agents? + +> Not in the first beta. The public name is provider-neutral, but the current +> implementation is focused on Codex CLI. We do not want to promise broader +> provider support before the Codex setup and reliability work is stable. +> Disclosure: we build CodePilot. + +### How should a tester report a problem? + +> Please include the step that failed, what you expected, what happened, and the +> app/build version. Do not post gateway URLs, bearer tokens, account names, +> private screenshots, local paths, or raw logs. Sanitize first, then use the +> public issue tracker at [PUBLIC_REPOSITORY_URL]/issues. Disclosure: we build +> CodePilot. + +### What kind of feedback is useful? + +> The most useful beta feedback is concrete: where setup became unclear, whether +> recovery text led to a fix, and which thread or turn action did not match your +> expectation. Reproduction steps help much more than a general rating. +> Disclosure: we build CodePilot. + +### What will it cost? + +> The current community outreach is only about the public beta and product +> reliability. We are not making pricing claims here. Disclosure: we build +> CodePilot. + +## Moderation-safe response principles + +- Answer the question before mentioning CodePilot. +- Mention CodePilot only when it is directly relevant; never hijack another + developer's post or an unrelated support thread. +- Disclose the relationship every time. +- Do not debate removals in public. If moderators request a change, stop and ask + a maintainer to review it. +- Do not ask for upvotes, coordinated comments, referrals, or private contact. +- Do not repeat a link after someone declines or expresses disinterest. +- Turn reproducible product feedback into a GitHub issue only after removing all + private information. diff --git a/gateway/codex_phone_gateway.py b/gateway/codex_phone_gateway.py index 835c818e..77d2c509 100755 --- a/gateway/codex_phone_gateway.py +++ b/gateway/codex_phone_gateway.py @@ -1861,6 +1861,48 @@ def apply_pinned_state(thread: dict, pinned_rank_by_id: dict[str, int]) -> dict: return copied +def curl_config_value(value: str) -> str: + return str(value).replace("\\", "\\\\").replace('"', '\\"').replace("\r", "").replace("\n", "") + + +def consume_codex_rate_limit_reset_credit(access_token: str, idempotency_key: str) -> dict: + token = str(access_token or "").strip() + if not token: + raise RuntimeError("Account auth has no access token") + + body = json.dumps({ + "creditType": "usage_limit", + "idempotencyKey": idempotency_key, + }, separators=(",", ":")) + config = "\n".join([ + 'url = "https://chatgpt.com/backend-api/wham/rate-limit-reset-credits/consume"', + 'request = "POST"', + 'header = "Accept: application/json"', + 'header = "Content-Type: application/json"', + f'header = "Authorization: Bearer {curl_config_value(token)}"', + f'data = "{curl_config_value(body)}"', + "", + ]) + completed = subprocess.run( + ["/usr/bin/curl", "-fsS", "--max-time", "20", "--config", "-"], + input=config, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + check=False, + ) + if completed.returncode != 0: + message = completed.stderr.strip() or completed.stdout.strip() or f"curl exited {completed.returncode}" + raise RuntimeError(f"Rate limit reset request failed: {truncate_text(message, 500)}") + if not completed.stdout.strip(): + return {} + try: + payload = json.loads(completed.stdout) + except json.JSONDecodeError as exc: + raise RuntimeError(f"Rate limit reset response was not JSON: {exc}") from exc + return payload if isinstance(payload, dict) else {"response": payload} + + class GatewayState: def __init__( self, @@ -2517,6 +2559,150 @@ def account_status_snapshot(self) -> dict: pass return snapshot + def consume_rate_limit_reset_credit(self, raw_name: str = "") -> dict: + requested_name = str(raw_name or "").strip() + if requested_name: + account_name = self.resolve_account_profile_name(requested_name) + result = self.consume_rate_limit_reset_credit_for_account(account_name) + self.record_rate_limit_reset_credit_consumed(account_name) + snapshot = self.account_status_snapshot() + snapshot["rateLimitReset"] = { + "accountName": account_name, + "result": result, + } + return snapshot + + client = self.app_server_client() + client.start() + result = client.request("account/rateLimitResetCredit/consume", { + "creditType": "usage_limit", + "idempotencyKey": f"codepilot-rate-limit-reset-{uuid.uuid4()}", + }) + snapshot = self.account_status_snapshot() + snapshot["rateLimitReset"] = result + return snapshot + + def consume_rate_limit_reset_credit_for_account(self, account_name: str) -> dict: + target_auth = self.accounts_dir / account_name / "auth.json" + if not target_auth.is_file(): + raise LookupError(f"No auth profile named {account_name}") + + previous_marker = None + previous_auth = None + if self.active_account_marker.is_file(): + previous_marker = self.active_account_marker.read_text(encoding="utf-8") + if self.active_auth_path.is_file(): + previous_auth = self.active_auth_path.read_bytes() + + previous_account = self.active_account_name() + needs_restore = account_name != previous_account or target_auth.read_bytes() != (previous_auth or b"") + idempotency_key = f"codepilot-rate-limit-reset-{account_name}-{uuid.uuid4()}" + + with RUN_LOCK: + if needs_restore and self.has_running_jobs(): + raise RuntimeError("Cannot reset a different account while a Codex turn is running") + + try: + if needs_restore: + self.install_account_for_app_server_context(account_name, target_auth) + return self.consume_active_app_server_rate_limit_reset_credit(idempotency_key) + finally: + if needs_restore: + self.restore_app_server_account_context(previous_auth, previous_marker) + + def consume_active_app_server_rate_limit_reset_credit(self, idempotency_key: str) -> dict: + client = self.app_server_client() + client.start() + return client.request("account/rateLimitResetCredit/consume", { + "creditType": "usage_limit", + "idempotencyKey": idempotency_key, + }) + + def install_account_for_app_server_context(self, account_name: str, profile_auth: Path): + with self._app_server_lock: + self._close_app_server_client_locked() + with self.auth_file_lock(): + self.sync_active_auth_to_active_profile() + self.install_auth_file(profile_auth, self.active_auth_path) + self.active_account_marker.parent.mkdir(parents=True, exist_ok=True) + self.active_account_marker.write_text(account_name + "\n", encoding="utf-8") + + def restore_app_server_account_context(self, previous_auth: bytes | None, previous_marker: str | None): + with self._app_server_lock: + self._close_app_server_client_locked() + with self.auth_file_lock(): + if previous_auth is None: + try: + self.active_auth_path.unlink() + except FileNotFoundError: + pass + else: + self.write_active_auth_bytes(previous_auth) + + if previous_marker is None: + try: + self.active_account_marker.unlink() + except FileNotFoundError: + pass + else: + self.active_account_marker.parent.mkdir(parents=True, exist_ok=True) + self.active_account_marker.write_text(previous_marker, encoding="utf-8") + + def write_active_auth_bytes(self, payload: bytes): + self.active_auth_path.parent.mkdir(parents=True, exist_ok=True) + fd, tmp_name = tempfile.mkstemp( + prefix=".auth.json.codex-phone-restore.", + suffix=".tmp", + dir=str(self.active_auth_path.parent), + ) + tmp_path = Path(tmp_name) + try: + with os.fdopen(fd, "wb") as handle: + handle.write(payload) + os.chmod(tmp_path, 0o600) + tmp_path.replace(self.active_auth_path) + os.chmod(self.active_auth_path, 0o600) + except Exception: + try: + tmp_path.unlink() + except OSError: + pass + raise + + def access_token_from_auth_file(self, auth_path: Path) -> str: + try: + payload = json.loads(auth_path.read_text(encoding="utf-8")) + except FileNotFoundError as exc: + raise LookupError("Account auth profile is missing") from exc + except json.JSONDecodeError as exc: + raise RuntimeError("Account auth profile is not valid JSON") from exc + + if not isinstance(payload, dict): + raise RuntimeError("Account auth profile is not valid") + tokens = payload.get("tokens") + if not isinstance(tokens, dict): + raise RuntimeError("Account auth profile has no tokens") + access_token = str(tokens.get("access_token") or "").strip() + if not access_token: + raise RuntimeError("Account auth profile has no access token") + return access_token + + def record_rate_limit_reset_credit_consumed(self, account_name: str): + usage = self.read_usage() + usage_key = account_name + for existing_key in usage: + if str(existing_key).casefold() == account_name.casefold(): + usage_key = existing_key + break + entry = usage.get(usage_key, {}) + if not isinstance(entry, dict): + entry = {} + remaining = optional_int(entry.get("rateLimitResetCreditsRemaining")) + if remaining is not None: + entry["rateLimitResetCreditsRemaining"] = max(0, remaining - 1) + usage[usage_key] = entry + write_json_object_atomic(self.usage_path, usage) + def ensure_plugin_connectivity(self) -> dict: status = { "source": str(self.mobile_codex_config_path), @@ -2895,22 +3081,9 @@ def live_activity_content_state(self, snapshot: dict) -> dict: accounts = [item for item in snapshot.get("accounts", []) if isinstance(item, dict)] buckets = [] for account in accounts: - if account.get("fiveHourRemainingPercent") is not None or account.get("fiveHourResetsAt") is not None: - buckets.append({ - "remaining": account.get("fiveHourRemainingPercent"), - "resetAt": account.get("fiveHourResetsAt"), - "windowMins": account.get("fiveHourWindowMins"), - "label": "5h", - "authStale": bool(account.get("authStale")), - }) - elif account.get("weeklyRemainingPercent") is not None or account.get("weeklyResetsAt") is not None: - buckets.append({ - "remaining": account.get("weeklyRemainingPercent"), - "resetAt": account.get("weeklyResetsAt"), - "windowMins": account.get("weeklyWindowMins"), - "label": "weekly", - "authStale": bool(account.get("authStale")), - }) + bucket = self.account_credit_bucket(account) + if bucket is not None: + buckets.append(bucket) available = [item for item in buckets if not item["authStale"]] reported = [item for item in available if item["remaining"] is not None] remaining = [max(0, min(100, int(item["remaining"]))) for item in reported] @@ -2953,6 +3126,61 @@ def live_activity_content_state(self, snapshot: dict) -> dict: "generatedAt": generated_at, } + def account_credit_bucket(self, account: dict) -> dict | None: + windows = [] + if account.get("fiveHourRemainingPercent") is not None or account.get("fiveHourResetsAt") is not None: + windows.append({ + "remaining": account.get("fiveHourRemainingPercent"), + "resetAt": account.get("fiveHourResetsAt"), + "windowMins": account.get("fiveHourWindowMins"), + "label": "5h", + }) + if account.get("weeklyRemainingPercent") is not None or account.get("weeklyResetsAt") is not None: + windows.append({ + "remaining": account.get("weeklyRemainingPercent"), + "resetAt": account.get("weeklyResetsAt"), + "windowMins": account.get("weeklyWindowMins"), + "label": "weekly", + }) + if not windows: + return None + + known_remaining = [ + max(0, min(100, int(window["remaining"]))) + for window in windows + if window.get("remaining") is not None + ] + effective_remaining = min(known_remaining) if known_remaining else None + label = str(windows[0].get("label") or "credit") + reset_at = None + window_mins = windows[0].get("windowMins") + + if effective_remaining is not None and effective_remaining > 0: + for window in windows: + if window.get("remaining") is not None and max(0, min(100, int(window["remaining"]))) == effective_remaining: + label = str(window.get("label") or label) + window_mins = window.get("windowMins") + break + else: + depleted = [ + window for window in windows + if window.get("remaining") is not None + and int(window.get("remaining") or 0) <= 0 + and window.get("resetAt") is not None + ] + limiting = max(depleted, key=lambda item: int(item.get("resetAt") or 0), default=windows[0]) + label = str(limiting.get("label") or label) + reset_at = limiting.get("resetAt") + window_mins = limiting.get("windowMins") + + return { + "remaining": effective_remaining, + "resetAt": reset_at, + "windowMins": window_mins, + "label": label, + "authStale": bool(account.get("authStale")), + } + def publish_live_activity_state(self, snapshot: dict): registrations = self.read_live_activities() if not registrations: @@ -3823,6 +4051,7 @@ def account_status(self, name: str, usage_entry, active_account: str) -> dict: "weeklyUsedPercent": optional_int(usage.get("weeklyLimitUsedPercent")), "weeklyWindowMins": optional_int(usage.get("weeklyLimitWindowMins")), "weeklyResetsAt": epoch_seconds(usage.get("weeklyLimitResetsAt")), + "rateLimitResetCreditsRemaining": optional_int(usage.get("rateLimitResetCreditsRemaining")), "lastRefreshAt": epoch_seconds(usage.get("lastRateLimitRefreshAt")), "lastUsedAt": epoch_seconds(usage.get("lastUsedAt")), "lastLimitAt": epoch_seconds(usage.get("lastLimitAt")), @@ -4491,6 +4720,12 @@ def do_POST(self): json_response(self, 200, snapshot) return + if len(parts) == 3 and parts[0] == "api" and parts[1] == "accounts" and parts[2] == "rate-limit-reset": + body = decode_body(self) + snapshot = self.state().consume_rate_limit_reset_credit(str(body.get("name", ""))) + json_response(self, 200, snapshot) + return + if len(parts) == 4 and parts[0] == "api" and parts[1] == "accounts" and parts[2] == "auth" and parts[3] == "refresh": body = decode_body(self) snapshot = self.state().refresh_account_auth_with_access_token( diff --git a/gateway/test_codex_phone_gateway.py b/gateway/test_codex_phone_gateway.py index 52c91aea..e80280b6 100644 --- a/gateway/test_codex_phone_gateway.py +++ b/gateway/test_codex_phone_gateway.py @@ -33,6 +33,24 @@ def start(self): raise RuntimeError("app-server disabled for test") +class RecordingRateLimitResetAppServerClient: + def __init__(self): + self.started = False + self.requests = [] + self.closed = False + + def start(self): + self.started = True + return {"ok": True} + + def request(self, method, params=None): + self.requests.append((method, params or {})) + return {"consumed": True} + + def close(self): + self.closed = True + + class RecordingPushNotifier: def __init__(self): self.sent = [] @@ -1135,6 +1153,7 @@ def test_account_statuses_include_profiles_usage_and_active_marker(self): "weeklyLimitRemainingPercent": 45, "weeklyLimitUsedPercent": 55, "weeklyLimitResetsAt": "2026-05-17T19:42:05Z", + "rateLimitResetCreditsRemaining": 3, "lastRateLimitRefreshAt": "2026-05-16T19:18:02Z", "limitHits": 4, "automaticSwitches": 2, @@ -1157,6 +1176,7 @@ def test_account_statuses_include_profiles_usage_and_active_marker(self): self.assertTrue(statuses["Main"]["authStale"]) self.assertEqual(statuses["Main"]["fiveHourRemainingPercent"], 12) self.assertEqual(statuses["Main"]["weeklyRemainingPercent"], 45) + self.assertEqual(statuses["Main"]["rateLimitResetCreditsRemaining"], 3) self.assertEqual(statuses["Main"]["fiveHourResetsAt"], 1778973006) finally: gateway.DEFAULT_SWITCHER_HOME = old_home @@ -1207,6 +1227,94 @@ def test_switch_account_persists_refreshed_active_auth_before_installing_next_ac gateway.JOBS.update(old_jobs) gateway.DEFAULT_SWITCHER_HOME = old_home + def test_consume_rate_limit_reset_credit_calls_app_server_and_returns_status(self): + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + codex_home = tmp_path / "codex" + switcher_home = tmp_path / "switcher" + accounts_dir = switcher_home / "accounts" + codex_home.mkdir() + (accounts_dir / "Main").mkdir(parents=True) + (accounts_dir / "Main" / "auth.json").write_text('{"account":"main"}', encoding="utf-8") + (codex_home / "auth.json").write_text('{"account":"main"}', encoding="utf-8") + (switcher_home / "active-account.txt").write_text("Main\n", encoding="utf-8") + + old_home = gateway.DEFAULT_SWITCHER_HOME + gateway.DEFAULT_SWITCHER_HOME = switcher_home + try: + state = GatewayState(tmp_path / "codex", "token", Path("/missing-codex"), False) + client = RecordingRateLimitResetAppServerClient() + state._app_server_client = client + state._app_server_auth_fingerprint = state.active_auth_fingerprint() + + with mock.patch("codex_phone_gateway.uuid.uuid4", return_value="reset-id"): + snapshot = state.consume_rate_limit_reset_credit() + + self.assertTrue(client.started) + self.assertEqual( + client.requests, + [( + "account/rateLimitResetCredit/consume", + { + "creditType": "usage_limit", + "idempotencyKey": "codepilot-rate-limit-reset-reset-id", + }, + )], + ) + self.assertEqual(snapshot["activeAccount"], "Main") + self.assertEqual(snapshot["rateLimitReset"]["consumed"], True) + finally: + gateway.DEFAULT_SWITCHER_HOME = old_home + + def test_consume_rate_limit_reset_credit_for_named_account_temporarily_switches_and_restores(self): + with tempfile.TemporaryDirectory() as tmp: + tmp_path = Path(tmp) + codex_home = tmp_path / "codex" + switcher_home = tmp_path / "switcher" + accounts_dir = switcher_home / "accounts" + codex_home.mkdir() + (accounts_dir / "Main").mkdir(parents=True) + (accounts_dir / "Free").mkdir(parents=True) + main_auth = json.dumps({"tokens": {"account_id": "main", "access_token": "main-token"}}) + free_auth = json.dumps({"tokens": {"account_id": "free", "access_token": "free-token"}}) + (accounts_dir / "Main" / "auth.json").write_text(main_auth, encoding="utf-8") + (accounts_dir / "Free" / "auth.json").write_text(free_auth, encoding="utf-8") + (codex_home / "auth.json").write_text(main_auth, encoding="utf-8") + (switcher_home / "active-account.txt").write_text("Main\n", encoding="utf-8") + (switcher_home / "usage.json").write_text(json.dumps({ + "Free": {"rateLimitResetCreditsRemaining": 2} + }), encoding="utf-8") + + old_home = gateway.DEFAULT_SWITCHER_HOME + gateway.DEFAULT_SWITCHER_HOME = switcher_home + try: + state = GatewayState(codex_home, "token", Path("/missing-codex"), False) + client = RecordingRateLimitResetAppServerClient() + + with mock.patch("codex_phone_gateway.uuid.uuid4", return_value="reset-id"), \ + mock.patch.object(state, "app_server_client", return_value=client): + snapshot = state.consume_rate_limit_reset_credit("Free") + + self.assertTrue(client.started) + self.assertEqual( + client.requests, + [( + "account/rateLimitResetCredit/consume", + { + "creditType": "usage_limit", + "idempotencyKey": "codepilot-rate-limit-reset-Free-reset-id", + }, + )], + ) + self.assertEqual(snapshot["activeAccount"], "Main") + statuses = {account["name"]: account for account in snapshot["accounts"]} + self.assertEqual(statuses["Free"]["rateLimitResetCreditsRemaining"], 1) + self.assertEqual(snapshot["rateLimitReset"]["accountName"], "Free") + self.assertEqual((switcher_home / "active-account.txt").read_text(encoding="utf-8"), "Main\n") + self.assertEqual((codex_home / "auth.json").read_text(encoding="utf-8"), main_auth) + finally: + gateway.DEFAULT_SWITCHER_HOME = old_home + def test_parse_mcp_list_output_marks_reconnectable_auth_states(self): state = GatewayState(Path("/tmp/codex"), "token", Path("/missing-codex"), False) output = """Name Url Bearer Token Env Var Status Auth @@ -1471,6 +1579,32 @@ def test_unchanged_live_activity_state_is_not_pushed_twice(self): finally: gateway.DEFAULT_SWITCHER_HOME = old_home + def test_live_activity_uses_limiting_account_window(self): + state = GatewayState(Path("/tmp/codex"), "token", Path("/missing-codex"), False) + now = 1_800_000_000 + weekly_reset = now + 604_800 + + content = state.live_activity_content_state({ + "generatedAt": now, + "accounts": [{ + "name": "Main", + "fiveHourRemainingPercent": 99, + "fiveHourResetsAt": now + 3_600, + "fiveHourWindowMins": 300, + "weeklyRemainingPercent": 0, + "weeklyResetsAt": weekly_reset, + "weeklyWindowMins": 10_080, + "authStale": False, + }], + }) + + self.assertEqual(content["kind"], "refilling") + self.assertIsNone(content["percent"]) + self.assertEqual(content["progress"], 0) + self.assertEqual(content["usableAccountCount"], 0) + self.assertEqual(content["nextRefreshAt"], weekly_reset) + self.assertEqual(content["refreshLabel"], "weekly") + def test_apns_notifier_uses_certificate_credentials_from_environment(self): with tempfile.TemporaryDirectory() as tmp: tmp_path = Path(tmp) diff --git a/ios/CodexPhone/CodexPhone/CodexPhoneApp.swift b/ios/CodexPhone/CodexPhone/CodexPhoneApp.swift index b09eba29..fd7e47b4 100644 --- a/ios/CodexPhone/CodexPhone/CodexPhoneApp.swift +++ b/ios/CodexPhone/CodexPhone/CodexPhoneApp.swift @@ -2235,6 +2235,8 @@ struct AccountStatusView: View { @State private var refreshTargetAccount: AccountUsageStatus? @State private var reconnectTargetServer: MCPServerStatus? @State private var isAddingAccount = false + @State private var rateLimitResetTargetAccount: AccountUsageStatus? + @State private var showRateLimitResetConfirmation = false var body: some View { NavigationStack { @@ -2260,13 +2262,17 @@ struct AccountStatusView: View { AccountStatusRow( account: account, switchingAccountName: model.switchingAccountName, - refreshingAuthAccountName: model.refreshingAuthAccountName + refreshingAuthAccountName: model.refreshingAuthAccountName, + resettingRateLimitAccountName: model.resettingRateLimitAccountName ) { Task { await model.switchAccount(named: account.name, baseURL: gatewayURL, token: gatewayToken) } } onRefreshAuth: { refreshTargetAccount = account + } onResetRateLimit: { + rateLimitResetTargetAccount = account + showRateLimitResetConfirmation = true } } } @@ -2313,6 +2319,23 @@ struct AccountStatusView: View { .task { await model.pollAccountStatus(baseURL: gatewayURL, token: gatewayToken) } + .confirmationDialog( + "Use a reset credit for \(displayValue(rateLimitResetTargetAccount?.name ?? ""))?", + isPresented: $showRateLimitResetConfirmation, + titleVisibility: .visible + ) { + Button("Use Reset Credit") { + let account = rateLimitResetTargetAccount + Task { + if let account { + await model.resetRateLimit(for: account.name, baseURL: gatewayURL, token: gatewayToken) + } + } + } + Button("Cancel", role: .cancel) {} + } message: { + Text("This asks Codex to consume one available rate limit reset credit on that account, without switching accounts.") + } .sheet(item: $refreshTargetAccount) { account in AccountAuthRefreshSheet( model: model, @@ -2594,21 +2617,27 @@ struct AccountStatusRow: View { let account: AccountUsageStatus let switchingAccountName: String? let refreshingAuthAccountName: String? + let resettingRateLimitAccountName: String? let onSwitch: (() -> Void)? let onRefreshAuth: (() -> Void)? + let onResetRateLimit: (() -> Void)? init( account: AccountUsageStatus, switchingAccountName: String? = nil, refreshingAuthAccountName: String? = nil, + resettingRateLimitAccountName: String? = nil, onSwitch: (() -> Void)? = nil, - onRefreshAuth: (() -> Void)? = nil + onRefreshAuth: (() -> Void)? = nil, + onResetRateLimit: (() -> Void)? = nil ) { self.account = account self.switchingAccountName = switchingAccountName self.refreshingAuthAccountName = refreshingAuthAccountName + self.resettingRateLimitAccountName = resettingRateLimitAccountName self.onSwitch = onSwitch self.onRefreshAuth = onRefreshAuth + self.onResetRateLimit = onResetRateLimit } var body: some View { @@ -2638,6 +2667,22 @@ struct AccountStatusRow: View { .disabled(refreshingAuthAccountName != nil) .accessibilityLabel("Refresh login for \(account.name)") } + if let onResetRateLimit, (account.rateLimitResetCreditsRemaining ?? 0) > 0 { + Button { + onResetRateLimit() + } label: { + if resettingRateLimitAccountName == account.name { + ProgressView() + .controlSize(.small) + } else { + Image(systemName: "arrow.counterclockwise.circle") + } + } + .buttonStyle(.bordered) + .controlSize(.small) + .disabled(resettingRateLimitAccountName != nil) + .accessibilityLabel("Use reset credit for \(account.name)") + } if let onSwitch, !account.isActive { Button { onSwitch() @@ -2684,6 +2729,9 @@ struct AccountStatusRow: View { ViewThatFits(in: .horizontal) { HStack(spacing: 12) { + if let resetCredits = account.rateLimitResetCreditsRemaining { + usageCounter("Reset credits", resetCredits) + } usageCounter("Limit hits", account.limitHits) usageCounter("Auto switches", account.automaticSwitches) usageCounter("Manual switches", account.manualSwitches) @@ -2692,6 +2740,9 @@ struct AccountStatusRow: View { } } VStack(alignment: .leading, spacing: 3) { + if let resetCredits = account.rateLimitResetCreditsRemaining { + usageCounter("Reset credits", resetCredits) + } usageCounter("Limit hits", account.limitHits) usageCounter("Auto switches", account.automaticSwitches) usageCounter("Manual switches", account.manualSwitches) @@ -2900,22 +2951,59 @@ struct AccountCreditBucket { init?(account: AccountUsageStatus) { accountName = account.name authStale = account.authStale - if account.fiveHourRemainingPercent != nil || account.fiveHourResetsAt != nil { - label = "5h" - remainingPercent = account.fiveHourRemainingPercent - resetAt = account.fiveHourResetsAt - windowMins = account.fiveHourWindowMins - } else if account.weeklyRemainingPercent != nil || account.weeklyResetsAt != nil { - label = "weekly" - remainingPercent = account.weeklyRemainingPercent - resetAt = account.weeklyResetsAt - windowMins = account.weeklyWindowMins - } else { + + let windows = [ + CreditWindow( + label: "5h", + remainingPercent: account.fiveHourRemainingPercent, + resetAt: account.fiveHourResetsAt, + windowMins: account.fiveHourWindowMins + ), + CreditWindow( + label: "weekly", + remainingPercent: account.weeklyRemainingPercent, + resetAt: account.weeklyResetsAt, + windowMins: account.weeklyWindowMins + ) + ].filter { $0.remainingPercent != nil || $0.resetAt != nil } + + guard !windows.isEmpty else { return nil } + + let knownRemaining = windows.compactMap(\.remainingPercent).map { max(0, min(100, $0)) } + remainingPercent = knownRemaining.min() + + if let effectiveRemaining = remainingPercent, effectiveRemaining > 0 { + let displayWindow = windows.first { $0.remainingPercent == effectiveRemaining } + ?? windows.first + label = displayWindow?.label ?? "credit" + resetAt = nil + windowMins = displayWindow?.windowMins + return + } + + let depletedWindows = windows.filter { window in + guard let remaining = window.remainingPercent else { return false } + return remaining <= 0 && window.resetAt != nil + } + let limitingWindow = depletedWindows.max { left, right in + (left.resetAt ?? 0) < (right.resetAt ?? 0) + } ?? windows.first + + label = limitingWindow?.label ?? "credit" + resetAt = limitingWindow?.resetAt + windowMins = limitingWindow?.windowMins } } +private struct CreditWindow { + let label: String + let remainingPercent: Int? + let resetAt: Int? + let windowMins: Int? +} + struct SignupURL: Identifiable { let id: String let url: URL @@ -3689,6 +3777,7 @@ final class CodexPhoneModel: ObservableObject { @Published var switchingAccountName: String? @Published var refreshingAuthAccountName: String? @Published var addingAccountName: String? + @Published var resettingRateLimitAccountName: String? @Published var errorMessage: String? private var pollingJobIDs: Set = [] @@ -3830,6 +3919,25 @@ final class CodexPhoneModel: ObservableObject { } } + func resetRateLimit(for name: String, baseURL: String, token: String) async -> Bool { + let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) + guard !token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else { return false } + guard !trimmedName.isEmpty else { return false } + guard resettingRateLimitAccountName == nil else { return false } + resettingRateLimitAccountName = trimmedName + defer { resettingRateLimitAccountName = nil } + do { + let response = try await client.consumeRateLimitResetCredit(accountName: trimmedName, baseURL: baseURL, token: token) + applyAccountStatus(response) + await flushQueuedPromptsIfPossible(baseURL: baseURL, token: token) + errorMessage = "Rate limit reset requested for \(trimmedName)." + return true + } catch { + report(error) + return false + } + } + func refreshAccountAuth(named name: String, accessToken: String, baseURL: String, token: String) async -> Bool { let trimmedName = name.trimmingCharacters(in: .whitespacesAndNewlines) let trimmedAccessToken = accessToken.trimmingCharacters(in: .whitespacesAndNewlines) @@ -4526,6 +4634,16 @@ struct CodexGatewayClient { ) } + func consumeRateLimitResetCredit(accountName: String, baseURL: String, token: String) async throws -> AccountStatusResponse { + try await request( + "/api/accounts/rate-limit-reset", + method: "POST", + body: RateLimitResetRequest(name: accountName), + baseURL: baseURL, + token: token + ) + } + func refreshAccountAuth(name: String, accessToken: String, baseURL: String, token: String) async throws -> AccountStatusResponse { try await request( "/api/accounts/auth/refresh", @@ -4880,6 +4998,10 @@ struct SwitchAccountRequest: Encodable { let name: String } +struct RateLimitResetRequest: Encodable { + let name: String +} + struct RefreshAccountAuthRequest: Encodable { let name: String let accessToken: String @@ -5567,6 +5689,7 @@ struct AccountUsageStatus: Decodable, Identifiable, Hashable { let weeklyUsedPercent: Int? let weeklyWindowMins: Int? let weeklyResetsAt: Int? + let rateLimitResetCreditsRemaining: Int? let lastRefreshAt: Int? let lastUsedAt: Int? let lastLimitAt: Int? diff --git a/ios/CodexPhone/CodexPhoneTests/RemoteDesktopTests.swift b/ios/CodexPhone/CodexPhoneTests/RemoteDesktopTests.swift index 1b695aa8..1524b736 100644 --- a/ios/CodexPhone/CodexPhoneTests/RemoteDesktopTests.swift +++ b/ios/CodexPhone/CodexPhoneTests/RemoteDesktopTests.swift @@ -42,15 +42,6 @@ final class RemoteDesktopTests: XCTestCase { XCTAssertFalse(canStartRemoteDesktop(statusText: "Host reachable, relay available")) } - func testGatewayRootURLRequiresHTTPOrHTTPSWithHost() throws { - let url = try gatewayRootURL(from: " https://codepilot.example.com ") - - XCTAssertEqual(url.absoluteString, "https://codepilot.example.com") - assertInvalidGatewayRootURL("codepilot.example.com") - assertInvalidGatewayRootURL("file:///tmp/codepilot") - assertInvalidGatewayRootURL("http:///missing-host") - } - func testMacLocalWebURLDetectionOnlyAcceptsLoopbackHTTPURLs() throws { XCTAssertTrue(isMacLocalWebURL(try XCTUnwrap(URL(string: "http://localhost:3000")))) XCTAssertTrue(isMacLocalWebURL(try XCTUnwrap(URL(string: "http://127.0.0.1:5173/path")))) diff --git a/ios/CodexPhone/CodexPhoneTests/TotalCreditActivityTests.swift b/ios/CodexPhone/CodexPhoneTests/TotalCreditActivityTests.swift index a83363db..c9285cb7 100644 --- a/ios/CodexPhone/CodexPhoneTests/TotalCreditActivityTests.swift +++ b/ios/CodexPhone/CodexPhoneTests/TotalCreditActivityTests.swift @@ -33,6 +33,29 @@ final class TotalCreditActivityTests: XCTestCase { XCTAssertEqual(state.refreshLabel, "5h") } + func testWeeklyExhaustionLimitsFiveHourCredit() { + let weeklyResetAt = Int(now.timeIntervalSince1970) + 604_800 + let state = TotalCreditStatus( + accounts: [ + account( + name: "One", + remaining: 99, + resetAt: Int(now.timeIntervalSince1970) + 3_600, + weeklyRemaining: 0, + weeklyResetAt: weeklyResetAt + ) + ], + now: now + ).activityState + + XCTAssertEqual(state.kind, .refilling) + XCTAssertNil(state.percent) + XCTAssertEqual(state.progress, 0, accuracy: 0.001) + XCTAssertEqual(state.usableAccountCount, 0) + XCTAssertEqual(state.nextRefreshAt, weeklyResetAt) + XCTAssertEqual(state.refreshLabel, "weekly") + } + func testAllStaleAccountsRequireAuthentication() { let state = TotalCreditStatus( accounts: [account(name: "Private Account", remaining: 80, authStale: true)], @@ -99,6 +122,8 @@ final class TotalCreditActivityTests: XCTestCase { name: String, remaining: Int?, resetAt: Int? = nil, + weeklyRemaining: Int? = nil, + weeklyResetAt: Int? = nil, authStale: Bool = false ) -> AccountUsageStatus { AccountUsageStatus( @@ -108,10 +133,11 @@ final class TotalCreditActivityTests: XCTestCase { fiveHourUsedPercent: remaining.map { 100 - $0 }, fiveHourWindowMins: 300, fiveHourResetsAt: resetAt, - weeklyRemainingPercent: nil, - weeklyUsedPercent: nil, - weeklyWindowMins: nil, - weeklyResetsAt: nil, + weeklyRemainingPercent: weeklyRemaining, + weeklyUsedPercent: weeklyRemaining.map { 100 - $0 }, + weeklyWindowMins: weeklyRemaining == nil && weeklyResetAt == nil ? nil : 10_080, + weeklyResetsAt: weeklyResetAt, + rateLimitResetCreditsRemaining: nil, lastRefreshAt: nil, lastUsedAt: nil, lastLimitAt: nil, diff --git a/ops/agents/community-drafts/2026-07-01-codepilot-beta-drafts.md b/ops/agents/community-drafts/2026-07-01-codepilot-beta-drafts.md new file mode 100644 index 00000000..1170d124 --- /dev/null +++ b/ops/agents/community-drafts/2026-07-01-codepilot-beta-drafts.md @@ -0,0 +1,1069 @@ +# CodePilot Community Drafts - 2026-07-01 + +Status: draft only. Do not post publicly without explicit maintainer approval. + +Last rule review: 2026-07-19. + +Review method: checked public Reddit rule/sidebar/search-visible pages, moderator +announcements, removal notices, and recent promotion threads on 2026-07-18 and +re-checked the current `r/AI_Agents` and `r/SideProject` threads on 2026-07-19. +Re-check each target immediately before any +human-approved posting because subreddit rules and megathread formats change. + +Identity: `codepilotios` + +Scope: +- Transparent beta-focused community promotion for CodePilot. +- No account creation. +- No public posting. +- No paid subscription, pricing, or future commercial claims. +- No private hostnames, tokens, personal emails, or unreleased links. + +## Baseline Reddit Rules + +Reddit-wide rules require users to follow community rules, participate authentically, avoid spam/content manipulation, and avoid deceptive identity use: + +Reddit Help says promotional content is not automatically spam, but communities may ban promotion or apply a 10% self-promotion rule: + +Legacy Reddit self-promotion guidance still captures the expected culture: do not only submit your own links, do not ask for votes, disclose affiliation, and message moderators when unsure: + +Operational rules for this queue: +- Use the `codepilotios` identity only after a maintainer creates or approves it. +- Always disclose: "I am the maker / creator of CodePilot." +- Post at most one CodePilot promotion per community unless the community explicitly has a recurring self-promotion thread. +- Never ask for upvotes. +- Prefer comments in approved self-promotion or feedback threads before standalone posts. +- If a subreddit rule is ambiguous, ask moderators before posting. + +## Communities Researched + +| Community | Fit | Rule summary | Recommendation | +| --- | --- | --- | --- | +| `r/ChatGPTCoding` | High topical fit, restricted and thread-gated | The community currently says only approved users can contribute. Its rules route service-style promotion to the designated self-promotion thread unless a main-feed sponsorship is approved through modmail. The current official thread remains visible and permits one promotion per project, but visible removals also show account-karma filtering. Sources: and | Hold unless a maintainer confirms that the approved `codepilotios` identity is already allowed to contribute. If eligible, use only the current self-promotion thread after confirming that it is still open. Do not request contributor status or sponsorship solely for this unattended run. Human approval remains required before posting. | +| `r/TestFlight` | High once the public beta link is live | Live rules require posts to concern a TestFlight app, allow only TestFlight links, require an app-name title without tags such as `[Tester]` or `[Recruiting]`, require platform flair, and ask developers not to flood the feed with repeat posts. Source: | Best direct tester-recruitment target after the public TestFlight link is verified and approved. Use `iOS` flair, keep the title to the app name plus a short message, and put later updates in comments rather than reposting. | +| `r/BetaTests` | Medium | The community welcomes product beta-testing and feedback posts, but prohibits spam and low-effort submissions. Posting accounts must be at least 24 hours old and have at least 2 combined Reddit karma. The sidebar says product posts do not need moderator pre-approval. Current automated posting guidance asks authors to explain the product clearly and ask specific feedback questions; it recommends adding a link when possible but does not make one mandatory. Sources: , , and | Useful secondary tester-recruitment target after the identity is approved and eligible. Use the specific no-link feedback draft first, disclose the maker relationship, and add only a separately approved public beta URL. Re-check the live rules immediately before posting. | +| `r/alphaandbetausers` | Medium | The live About page currently lists no community-specific rules beyond Reddit-wide policy, and recent posts include explicit iOS/TestFlight tester requests. Source: and recent example: | Useful secondary tester-recruitment target. Use the link-free, feedback-specific draft after maintainer approval; disclose the maker relationship and do not offer reciprocal testing or incentives that have not been approved. Re-check the live About page and recent moderation behavior immediately before posting. | +| `r/BetaTestersNeeded` | Not eligible for this run | The community is restricted to approved contributors and requires a post flair, a tester perk in the title and body, and a signup or beta link. It permits repeat promotion only after seven days. Source: | Hold. Do not request contributor approval, invent a perk, imply paid-tier value, or post an unapproved link. Reconsider only if a maintainer separately approves the identity, a concrete non-pricing perk, and a verified public beta URL. | +| `r/appledevelopers` | Medium for technical discussion, low for beta recruitment | Posts must concern Apple-platform development. Promotional content must be limited and disclose the developer relationship; the sidebar explicitly directs TestFlight apps to `r/TestFlight`. Source: | Do not cross-post the tester request here. Use `r/TestFlight` for recruitment. Consider this community later only for a substantive Apple-development discussion with maintainer approval and explicit maker disclosure. | +| `r/ShowMeYourApps` | Not eligible | The community accepts mobile-app promotion but its live rules explicitly prohibit AI content. Source: | Do not promote CodePilot there while the AI-content ban remains. Do not try to reframe the Codex companion as a non-AI app to bypass the rule. | +| `r/iosapps` | Not eligible | Requires 10 local karma, official App Store or TestFlight distribution, infrequent disclosed promotion, and either trust/transparency qualification or monthly-megathread use. More importantly, the current rules prohibit generative-AI and AI-wrapper apps and explicitly direct them to `r/GenAiApps`; the July 2026 policy likewise says AI-first apps do not belong in `r/iosapps`. Sources: and | Do not use either the main feed or the App Shelf for CodePilot promotion while this exclusion remains. Use `r/GenAiApps` as the rules-directed alternative after maintainer approval. | +| `r/iPhoneApps` | Low / hold until genuine participation | The live rules allow recommending your own iPhone app only when it is relevant to an existing discussion, clearly disclosed, and useful. Shared apps must be available on the Apple App Store and include details such as description and cost. A 2026-07-16 moderator announcement removed the Developer flair and says pure promotional drops will be removed; developers should participate and contribute before mentioning their app in context. Sources: and | Do not prepare a standalone launch post or use a new promotion-only account. Revisit only after the approved identity has genuine community participation and CodePilot has an approved App Store listing and status language. Use modmail, not direct moderator contact, if eligibility remains unclear. | +| `r/iOSBeta` | Not eligible | Current automated removals state that posts about third-party apps in beta or TestFlight are not allowed; the community is for iOS beta discussion rather than recruiting testers for individual apps. Recent examples: and | Do not post CodePilot or a TestFlight recruitment request there. Use `r/TestFlight` after the public beta link is verified and approved. | +| `r/GenAiApps` | Medium-high | The community is specifically for generative-AI apps. Current rules allow self-promotion when it provides value and context, require an appropriate flair, prohibit spam/duplicate or low-effort posts, require context for links, and prohibit unsafe links or personal information. Source: | Good text-first beta-feedback candidate after maintainer approval. Use the `iOS` flair, disclose the maker relationship, explain the Codex-specific workflow, and include no link until the public beta URL is approved. Re-check recent posts and flair options immediately before posting. | +| `r/AI_Agents` | Medium-high | The live rules permit limited self-promotion at roughly one in ten posts/comments, prohibit promotion-only accounts and low-context posts, require links to be placed in comments, and route project showcases to the weekly Project Display thread. The current weekly thread explicitly welcomes AI agents and LLM apps. Sources: and | Good agent-workflow feedback target only after the approved identity has genuine non-promotional participation. Use the weekly Project Display thread, disclose the maker relationship, and keep the first draft link-free unless a direct public beta or repository URL is separately approved. | +| `r/vibecoding` | Low / externally gated | CodePilot counts as a developer tool, and the live rules require developer-tool makers to obtain approval by joining the community on X, posting the tool there, and waiting for a moderator DM before making one introduction post. The subreddit also rejects fully generated low-effort content and requires educational detail for project posts. Sources: and | Hold. This run may not create or mutate accounts or post on non-GitHub external systems, so it cannot complete the X approval gate. Do not disguise CodePilot promotion as general discussion or a project breakdown. | +| `r/codex` | High | Community is specifically for OpenAI Codex tools, including Codex CLI, IDE Extension, and Codex in the Cloud. Current rules require posts to be directly related to Codex, use the right flair, avoid low-effort rants, and not use bots. Recent AMA thread required subreddit karma for comments. Sources: and | Strong fit, but treat as moderator-approval first because the post is maker-authored promotion. A maintainer must post manually; use text-only feedback framing unless mods approve a beta link. | +| `r/LLMDevs` | High for a technical project discussion | The community prioritizes substantive LLM/NLP material. Its current self-promotion clarification allows projects under noncommercial licenses without prior moderator approval, prohibits commercial promotion, and bans disguised advertising or fake discussion framing. Sources: and | Good technical candidate because CodePilot is source-available under the PolyForm Noncommercial License, but describe that license exactly rather than calling the project open source. Hold until a maintainer approves an accessible, privacy-audited repository URL and confirms that the live rule still treats this specific license as eligible. Use the transparent architecture-and-trust draft, not a generic tester request. | +| `r/SideProject` | Medium-high | The live About page currently shows no community-specific rules beyond Reddit-wide rules and says anyone may post. Project showcases and beta-feedback requests are common, and a current self-promotion thread explicitly invites projects and feedback. A recent high-engagement community discussion objects to promotion-only accounts and link drops. Sources: , , , and | Prefer the current self-promotion thread over a standalone post. Use the no-link, feedback-specific comment draft after maintainer approval, and re-check the thread and live About page immediately before posting. | +| `r/iOSProgramming` | Medium | App posts are Saturday-only and limited to one post per app per year. The live App Saturday guide requires `Tech Stack Used`, `Development Challenge + How You Solved It`, and `AI Disclosure` content. The live rule also asks authors not to post without previous community activity but does not state a numeric karma threshold. Sources: and | Approval required. Hold until Saturday and do not use a new/inactive `codepilotios` account. | +| `r/swift` | Medium | Self-promotion must be under 5% of the account's posts and comments in the subreddit. It is not allowed with fewer than 5 posts/comments in the sub or when the account is under 2 months old. Source: | Approval required. Do not post from a new `codepilotios` account. Use only after the account age, activity, and contribution-ratio thresholds are met. | +| `r/SwiftUI` | Low-medium for technical discussion only | Posts must be specifically about SwiftUI rather than general app feedback. App promotion is permitted only when source code is also provided, preferably through GitHub; low-effort showcases and questions without relevant code are discouraged. Source: | Do not use for tester recruitment. Consider only a focused SwiftUI implementation discussion after the relevant source, code excerpt, and public repository have passed launch review. Maintainer approval is still required. | +| `r/macapps` | Medium | Current front page shows active app posts with pricing/flair labels and the July 2026 App Pile megathread. Rule/sidebar snippets require 10 local karma, megathread promotion unless the account qualifies through trust/transparency, post approval, and PCP-style promotion. Recent megathreads require pricing and link fields. Sources: and | Hold. Current pricing/link requirements conflict with the no-pricing/no-unapproved-link launch constraint unless moderators approve a beta-feedback exception. | +| `r/OpenAI` | Medium-low | Search-visible rule text says self-promotion should stay under a 1/10 guideline, direct self-promotional project links are not allowed, and promotional project posts need context in text posts. Other current rule snippets show stricter enforcement language against solicitation/self-promotion. Sources: and | Approval required. Avoid direct link posts. Consider only a non-link discussion post after moderator approval. | +| `r/ChatGPTPro` | Medium for a technical power-user discussion | The community is for advanced, professional LLM workflows rather than basic support or generic promotion. Its published policy limits self-promotion to at most 10% of an account's community activity, requires clear value and affiliation disclosure, and recent removal notices show active enforcement against direct promotional links and accounts without enough non-promotional participation. Sources: , , and | Hold until the approved identity has genuine technical participation and safely meets the one-in-ten limit. Ask moderators before a maker-authored post, use the link-free architecture/workflow draft only if approved, and do not treat the community as a tester-recruitment feed. | +| `r/MacOS` | Medium | The March 2026 Developer Saturday policy permits one self-promotional post per user each Saturday from 00:00 through 23:59 UTC. It explicitly welcomes accessible GitHub repositories, which are scanned by GitHub-Guard, and requires affiliation disclosure, useful context, and more than a low-effort link drop. Source: | Candidate Saturday placement after maintainer approval. Use a transparent, context-rich beta-feedback post and link only to an approved, accessible, security-ready repository or distribution page. | +| `r/apple` | Medium reach, low immediate eligibility | Developer app self-promotion is allowed only on Sundays in California time and must be a substantive self-post with a link. The live rule requires organic participation; current automated removal notices define eligibility as at least 5 unrelated posts or comments in `r/apple` during the previous month and keep self-promotion at no more than 10% of activity. Sources: and a current removal notice quoting Rule 9: | Hold. Do not create activity or use a promotion-only identity to satisfy the gate. Reconsider only if an already-approved `codepilotios` identity independently meets the participation ratio, the post can be made during the Sunday window, and a direct official beta or repository URL is approved. | +| `r/macosprogramming` | Medium for a technical post | Posts must concern macOS software development. Open-source apps may be shared, but closed-source, paid, or IAP apps require prior moderator permission. The rules also prohibit repetitive promotion, link spam, and low-effort autogenerated posts. CodePilot is source-available under a noncommercial license rather than OSI open source, so the open-source exception must not be assumed. Sources: and | Moderator-first only. Ask whether a technical, text-first discussion of the Mac menu bar app and local gateway is acceptable. A maintainer must review and send the note manually, then rewrite/review the discussion copy before posting. | +| `r/indiehackers` | Medium for product validation | The live rules allow one self-promotional product post for feedback and critique rather than advertising. The rules call the required flair `SHOW IH`, while the visible flair filter currently says `Self Promotion`; moderator guidance also emphasizes contribution before promotion and rejects fake Q&A, karma farming, and artificial engagement. Sources: and | Held secondary option. Confirm the current flair and that the approved identity has genuine participation before using the one-time post. Use the link-free validation draft, disclose the maker relationship, and do not mention revenue, pricing, or ask for votes. | +| `r/selfhosted` | Low-medium later | Mobile apps are allowed only as companions to a self-hosted backend. Promoted apps must be production-ready and documented. Projects under 3 months old may be posted only in the current New Project Megathread; Wednesday has a separate exception for dashboards and tools that help self-hosters. Source: | Hold for now. CodePilot has a local gateway and user-owned tunnel, but this is not primarily a general self-hosted server product; ask moderators only after public docs and production readiness are stronger. | +| `r/github` self-promotion megathread | Medium | The designated recurring self-promotion thread accepts tools, libraries, and side projects hosted on GitHub. Comments should include a short project description, a GitHub repository link, and optionally the stack, main features, or contribution context. Source: | Candidate only after the public repository URL is approved, accessible, and privacy-audited. Use the megathread rather than a standalone promotional post, disclose the maker relationship, and ask for repository/setup feedback rather than votes. | +| `r/ClaudeAI` | Low | Project showcases must be built with Claude/Claude Code or specifically for Claude by the poster, be free to try, explain how Claude helped, use minimal promotional language, and come from an account with more than 50 karma. Source: | Do not post CodePilot promotion because this Codex-focused beta does not meet the stated Claude-project relevance gate. Only answer organically if directly relevant and approved by a maintainer. | +| Hacker News / Show HN | Medium, currently contributor-gated | Show HN is for something people can try; HN asks submitters not to use it primarily for promotion and not to post generated or AI-edited comments. HN is also temporarily restricting Show HN submissions and asks prospective submitters to become genuine contributors before posting an occasional project. Sources: , , and | Hold unless a maintainer confirms that an existing approved public identity is eligible. Do not create an HN account or manufacture participation for this launch. If eligible later, a maintainer must rewrite the outline manually and post only when the beta is directly usable. | +| Product Hunt | Medium later | Product Hunt recommends clear product pages, maker first comment, feedback requests rather than upvote requests, and warns against spamming communities where you have not been active. Sources: and | Not a first beta move. Requires account, launch assets, and pricing/status decisions, so hold for human approval. | + +## Rules That Require Approval Before Posting + +- Any public Reddit post, comment, or account profile must be approved by a maintainer per the launch plan. +- `r/ChatGPTCoding`: the community is currently restricted to approved contributors, and maker-authored service promotion belongs only in the current self-promotion thread. Hold unless a maintainer confirms that the approved `codepilotios` identity can contribute, the thread is still open, and the identity clears its account-karma filters. Main-feed promotion needs modmail/sponsorship approval; do not request contributor status or sponsorship in this unattended run. +- `r/TestFlight`: hold until there is a verified, approved public TestFlight link. Use only that link, select `iOS` flair, keep the title free of recruitment tags, and avoid repeat posts; later updates belong in the original post's comments. +- `r/BetaTests`: no moderator pre-approval is currently required, but launch-plan maintainer approval still is. Confirm that `codepilotios` is at least 24 hours old and has at least 2 combined Reddit karma. Keep the post specific to beta testing, constructive, and non-spammy; use the no-link draft unless a public beta URL is separately approved. +- `r/alphaandbetausers`: no community-specific rules are currently shown, but launch-plan maintainer approval still applies. Use the link-free tester-feedback draft, disclose the maker relationship, avoid unapproved incentives or test-for-test promises, and re-check the live rules and recent removals before posting. +- `r/BetaTestersNeeded`: hold. Posting requires approved-contributor status, a tester perk in the title and body, and a signup/test link. Those gates require maintainer decisions and external account action that this run must not infer or perform. +- `r/appledevelopers`: do not duplicate the beta-recruitment post; its rules direct TestFlight apps to `r/TestFlight`. Any later technical post must be substantive, limited, transparent, and maintainer-approved. +- `r/ShowMeYourApps`: do not post CodePilot there while its explicit no-AI-content rule remains. No moderator request or alternate framing is warranted for this beta campaign. +- `r/iosapps`: do not use either the main feed or the App Shelf. The current rules prohibit generative-AI and AI-wrapper apps and direct them to `r/GenAiApps`; re-check only if the rule changes. +- `r/iPhoneApps`: do not make a standalone promotional post. The Developer flair was removed on 2026-07-16, self-mentions must arise from genuine participation and add value, and shared apps must be available on the Apple App Store with approved cost/status details. Use modmail rather than contacting moderators directly if a later contextual mention is uncertain. +- `r/iOSBeta`: do not post third-party beta or TestFlight recruitment. Current automated removals explicitly reserve the community for iOS beta discussion; use `r/TestFlight` instead after link and maintainer approval. +- `r/GenAiApps`: general rules allow valuable self-promotion, but a maintainer must still approve the final post. Use the `iOS` flair, provide useful context, avoid repeat or low-effort promotion, and include no link until the public beta URL is approved. +- `r/AI_Agents`: use only the current weekly Project Display thread after the approved identity has genuine participation and its self-promotion ratio is safely below one in ten. Put any separately approved link in a reply rather than the project description, provide substantive workflow context, and have a maintainer post manually. +- `r/vibecoding`: do not post or prepare a disguised discussion placement. Developer-tool promotion requires prior approval through an X community post and moderator DM; satisfying that gate requires a maintainer-controlled external account action that this agent is not authorized to perform. +- `r/codex`: directly relevant to Codex, but ask moderators before a maker-authored beta-feedback post with any link; new-account karma filters may apply, and the explicit no-bots rule means a maintainer must post manually. +- `r/LLMDevs`: the published clarification allows noncommercial-licensed projects without prior moderator approval, but CodePilot must be described accurately as source-available under the PolyForm Noncommercial License rather than open source. A maintainer must approve the exact copy and an accessible, privacy-audited repository URL, confirm the live rule still covers that license, and post manually. Do not disguise the maker relationship or frame an advertisement as an organic question. +- `r/SideProject`: the live About page currently lists no community-specific rules, but community sentiment strongly disfavors promotion-only participation. Prefer the current self-promotion thread, post manually only after maintainer approval, disclose the maker relationship, and use the no-link feedback draft rather than a standalone launch post. +- `r/iOSProgramming`: Saturday-only app post, one app post per year, prior activity expected, and mandatory App Saturday content sections. The live rules do not currently state a numeric karma threshold, but eligibility must still be re-checked before posting. +- `r/swift`: do not self-promote from an account under 2 months old or with fewer than 5 posts/comments in the subreddit; self-promotional content must also remain below 5% of the account's posts and comments there. +- `r/SwiftUI`: no tester-recruitment post. A later technical discussion requires a concrete SwiftUI question, relevant source code, an approved public repository if linked, and maintainer approval. +- `r/macapps`: requires 10 local karma, trust/transparency qualification or monthly megathread use, and post approval. Current App Pile PCP format expects pricing and link fields, so posting needs moderator guidance while pricing/link status is intentionally withheld. +- `r/OpenAI`: direct self-promotional project links are not allowed; ask mods before any non-link discussion that mentions CodePilot. +- `r/MacOS`: Saturday-only from 00:00 through 23:59 UTC, one promotional post per user per week, explicit developer/affiliate disclosure, useful context, and no low-effort link drop. GitHub repositories are allowed but will be scanned, so any linked repository must be approved, accessible, and security-ready. +- `r/apple`: developer self-promotion is Sunday-only in California time and must be a substantive self-post with a direct link. Hold unless the approved identity already has at least 5 unrelated contributions in the community during the previous month and stays at or below the one-in-ten self-promotion ratio. Do not manufacture participation; approve the exact title, body, timing, and official URL before a maintainer posts manually. +- `r/macosprogramming`: prior moderator permission is required because CodePilot's noncommercial source-available license is not OSI open source. Any approved post must stay focused on macOS development, be technically substantive, and be reviewed manually to avoid low-effort autogenerated copy. +- `r/indiehackers`: only one product self-promotion is allowed, and it must seek feedback/critique rather than advertise. Confirm whether the live required flair is `SHOW IH` or `Self Promotion`, and wait until the approved identity has genuine community participation. Do not make revenue claims or manufacture engagement. +- `r/selfhosted`: hold until CodePilot has public docs and production-ready positioning that fits the community; projects under 3 months old belong only in the current New Project Megathread, and any maker-authored mention still needs moderator and maintainer approval. +- `r/github`: use only the designated self-promotion megathread and only after a maintainer approves an accessible, privacy-audited public repository URL. The comment must include that GitHub link, so a no-link placeholder must not be posted. +- `r/ClaudeAI`: do not promote this Codex-focused beta because it does not meet the community's Claude-built/Claude-focused showcase gate; eligible showcases also require more than 50 account karma. +- Hacker News: Show HN is temporarily restricted to people who have first become genuine contributors. Do not create an account or manufacture participation for this launch. If an existing approved public identity is eligible, a maintainer should still write the actual submission and comments manually because HN asks users not to post generated or AI-edited comments. +- Product Hunt: hold until account, maker identity, screenshots, launch URL, and current beta/pricing status are approved. + +## Recommended Approval Queue + +Use a staged rollout rather than sending substantially similar beta requests to +multiple communities at once. A maintainer should re-check the live target and +approve the exact copy immediately before every manual post or comment. + +1. **First placement:** use Draft 11 in `r/GenAiApps`. It is public, directly + relevant to generative-AI apps, and currently permits contextual, valuable + self-promotion. Use `iOS` flair, disclose the maker relationship, and keep it + link-free until the public beta URL is approved. +2. **Tester recruitment:** after the first placement produces useful discussion + and identity eligibility is confirmed, choose one of + Draft 15 for `r/BetaTests` or Draft 16 for `r/alphaandbetausers`; do not post + both at the same time. Wait for feedback before considering the other. +3. **Direct installation:** once a verified public Apple TestFlight URL is + approved, use Draft 10 in `r/TestFlight` with `iOS` flair and only that link. + Put later beta updates in the original post's comments rather than reposting. +4. **Technical follow-up:** after the repository URL is approved and + privacy-audited, consider Draft 19 in `r/LLMDevs`. Confirm that the live + noncommercial-license exception still covers CodePilot's exact license and + keep the post candid, technical, and creator-disclosed. +5. **Thread, moderator, or participation-gated communities:** consider the + current `r/ChatGPTCoding` self-promotion thread, `r/AI_Agents`, `r/codex`, + `r/ChatGPTPro`, `r/iOSProgramming`, `r/swift`, `r/MacOS`, `r/apple`, + `r/macosprogramming`, and `r/indiehackers` only after their thread, + activity, timing, moderator, account-filter, and maintainer gates are + satisfied. Keep all other held targets out of the launch queue unless their + rules or CodePilot's release status materially change. + +## Draft Reddit Profile + +Profile display name: + +```text +CodePilot iOS +``` + +Profile bio: + +```text +Creator-run beta account for CodePilot: a Mac + iPhone companion for running Codex sessions from a Mac you control. I am here to collect setup feedback from Codex, iOS, and Mac automation users. Please do not send tokens, private logs, or credentials. +``` + +Pinned profile post draft: + +```text +Hi, I am the maker of CodePilot. + +CodePilot is in beta. It connects a Mac menu bar app, a local token-protected gateway, and an iPhone companion so Codex users can check account/usage state, continue sessions from iPhone, upload files, and steer or stop active turns from a Mac they control. + +This account is for transparent beta feedback only. I will disclose my relationship whenever I mention CodePilot in a community. Please do not send credentials, bearer tokens, private logs, private hostnames, or files from your projects. If you try the beta and hit setup friction, sanitized steps and screenshots are the most useful feedback. +``` + +## Draft 1: `r/ChatGPTCoding` Self-Promotion Thread Comment + +Posting target: current or next `r/ChatGPTCoding` self-promotion thread. + +Approval status: needs maintainer approval before posting. Confirm that the +current thread remains open and that `codepilotios` can comment without an +account-karma removal. + +Rule notes: +- Fits the self-promotion thread. +- The community is currently restricted to approved contributors, and visible + thread removals also show account-karma filtering and possible manual review. +- Do not request contributor status solely for this unattended run. +- Use a comment in the thread, not a main-feed post, unless moderators explicitly approve otherwise. +- Do not mention selling access to models. +- Promote once per project. +- Expect karma filtering if `codepilotios` is new. + +```text +Hi, I am the maker of CodePilot. + +It is a beta Mac + iPhone companion for people already running Codex on their own Mac. The Mac side watches local Codex account/usage state and runs a token-protected local gateway. The iPhone side connects through a user-owned Cloudflare Tunnel to that gateway so you can check active account state, continue a session away from the desk, upload files, and steer or stop an active turn. + +I am looking for a small number of beta testers who already use Codex CLI on macOS and are willing to give blunt setup feedback. The areas I most want tested are: + +- whether the Mac gateway setup is understandable +- whether the iPhone connection/token flow is clear +- whether remote session control from iPhone actually solves a real workflow problem +- what errors or recovery steps are still confusing + +This is a beta feedback request, and I am not asking for upvotes. If this matches your workflow, reply here with what setup you use for Codex today, and I will share the approved beta link once it is ready for public distribution. +``` + +Moderator note if main-feed placement is desired later: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac + iPhone companion for people running Codex from a Mac they control. + +I saw the self-promotion rule and the designated promotion thread. For now I plan to use only that thread. If there is a future version that would be useful as a main-feed technical discussion, should I request sponsorship/mod approval first, or should all CodePilot mentions stay in the promotion thread? +``` + +## Draft 2: `r/codex` Moderator-First Beta Feedback Post + +Posting target: `r/codex` + +Approval status: moderator approval and maintainer approval required before posting. Do not include a beta link unless moderators explicitly approve it. + +Rule notes: +- Must be directly related to OpenAI Codex tools. +- Keep it high-signal and feedback-focused. +- A maintainer must post manually; the subreddit explicitly prohibits bots. +- New-account subreddit karma restrictions may block comments/posts. +- Disclose maker relationship. + +Moderator note draft: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac + iPhone companion for people who run Codex from a Mac they control. + +I saw that r/codex requires posts to be directly related to Codex. Would a text-only beta feedback post be acceptable if it focuses on Codex CLI workflow, local gateway security, and setup clarity rather than a launch link? + +I would disclose my relationship, avoid pricing language, avoid asking for votes, and only include a beta link if you explicitly approve that. +``` + +Discussion body if approved: + +```text +I am the maker of CodePilot, and I am looking for feedback from people who use Codex on macOS. + +The beta is built around a simple constraint: Codex stays on the Mac where the CLI session, auth files, account state, and project files already live. CodePilot adds a Mac menu bar app, a token-protected local gateway, and an iPhone client for status, files, notifications, and turn controls. + +For the current public-beta iPhone path, a user-owned Cloudflare Tunnel reaches the loopback-only gateway, and the phone still has to authenticate to it. I am trying to keep the trust boundary explicit instead of turning this into a hosted Codex proxy. + +The feedback I am looking for: + +- Would an iPhone companion for Codex sessions solve a real workflow problem for you? +- What would you need to verify before trusting a local gateway that touches Codex session state? +- Which setup step would make you stop: gateway token, tunnel setup, iOS pairing, file upload, or remote turn control? +- What documentation would you expect before trying a beta? + +This is a beta feedback request, not an upvote request. I am trying to make the beta safer and clearer before broader distribution. +``` + +## Draft 3: `r/SideProject` Standalone Feedback Post (Held Alternative) + +Posting target: `r/SideProject` + +Approval status: hold. Prefer Draft 13 in a current self-promotion thread. Use +this standalone alternative only if the thread is unavailable and a maintainer +explicitly approves standalone placement after re-checking the live community. + +Rule notes: +- Fit is strongest when framed as a specific side-project feedback request. +- Current community sentiment strongly disfavors promotion-only participation + and link drops, even though the live About page lists no specific rules. +- Do not ask friends, testers, or communities to upvote. +- Include only an approved public link if links are allowed at posting time; otherwise ask for replies and share the approved beta link only after maintainer approval. + +Title options: + +```text +I built an iPhone companion for running Codex sessions from my Mac +``` + +```text +Looking for feedback on CodePilot, a Mac + iPhone beta for Codex users +``` + +Body: + +```text +I am the maker of CodePilot, and I am looking for feedback from people who already use Codex on macOS. + +The problem I kept running into: coding-agent work is tied to the Mac where the CLI session, auth files, account state, and project files live. If I walk away, I still want to see whether a turn finished, check usage/account state, upload a file from my phone, or stop/steer the session without exposing the whole machine broadly. + +So I built a beta with three pieces: + +- a Mac menu bar app for local account/usage state and account switching +- a local token-protected Python gateway on the Mac +- an iPhone app that connects to the gateway for threads, files, status, and turn controls + +The current public-beta iPhone setup uses a user-owned Cloudflare Tunnel because the Mac gateway listens on loopback by default. The iOS app talks to that gateway, not directly to provider services. + +I am asking for setup feedback, not votes. I am trying to learn whether the setup is understandable and whether this solves a real problem for Codex users. + +If you use Codex CLI on macOS: what would make you trust or reject a setup like this? What would you want to see before installing a beta that touches local coding-agent credentials? +``` + +No-link variant if link placement is unclear: + +```text +I am the maker of CodePilot, a beta Mac + iPhone companion for people who run Codex on a Mac. + +I am not dropping a launch link here. I am trying to pressure-test the idea before wider distribution: Codex stays on the Mac, a token-protected loopback gateway exposes narrow session/status/file endpoints, and the current public-beta iPhone path reaches that gateway through a user-owned Cloudflare Tunnel for status, file upload, and turn controls. The provider login stays on the Mac. + +For people who build or use developer tools: would this solve a real workflow problem, or would the local gateway/auth-file aspect make you reject it? What would you need documented before trying a beta? +``` + +## Draft 4: `r/iOSProgramming` App Saturday Post + +Posting target: `r/iOSProgramming`, Saturday only. + +Approval status: needs maintainer approval before posting; do not post from a new or inactive account. + +Posting gate: Saturday only, one post per app per year, prior community activity, +and all three required sections below. Re-check the live rules before approval. + +Title: + +```text +I built a SwiftUI iPhone companion for controlling Codex sessions on my Mac +``` + +Body: + +```text +I am the maker of CodePilot, a TestFlight beta for people who run Codex on a Mac and want an iPhone companion for setup/status/session control. + +Tech Stack Used + +The iOS app is built with SwiftUI. It talks to a token-protected local Python gateway running on the user's Mac. The Mac app is a menu bar utility that watches local Codex account and usage state. For the current public-beta path, the iOS app reaches the loopback-only gateway through a user-owned Cloudflare Tunnel and still authenticates with a bearer token. + +The iPhone client currently focuses on connection setup, gateway health, thread/session status, file uploads, usage/account status, notifications, and controls for steering or stopping active turns. + +Development Challenge + How You Solved It + +The hard part was making remote control feel useful without pretending the phone owns the coding-agent session. The source of truth still lives on the Mac: auth files, project files, active turns, and account state. + +The solution was to keep the iOS app as a gateway client rather than a direct provider client. The gateway exposes narrow endpoints for thread state, uploads, health, account status, and turn controls. The iOS app stores only the gateway URL and token locally, then treats every setup failure as a recoverable connection state instead of a generic network error. + +The biggest area where I want feedback is onboarding clarity. A beta tester has to understand what is local, what is remote, what the token protects, and why they should not paste private logs or gateway tokens into issue reports. + +AI Disclosure + +AI-assisted. Parts of the project planning, copy, and implementation have been assisted by coding agents. Security-sensitive flows, gateway exposure, auth files, and release materials still need human review before broader release. + +I am looking for feedback from iOS/macOS developers who use coding agents: does this architecture feel understandable and reviewable? What would you need to see before trusting a beta that bridges an iPhone to a local Mac coding-agent gateway? +``` + +## Draft 5: `r/swift` Technical Discussion Post + +Posting target: `r/swift` + +Approval status: hold until `codepilotios` is at least 2 months old and has at least 5 posts/comments in `r/swift`, or moderators approve. If eligible, self-promotion must remain below 5% of the account's posts and comments in the subreddit. + +Posting note: do not include a link in the first version unless mods approve. Frame as a Swift architecture question, not a launch. + +Title: + +```text +How would you model connection state for a SwiftUI client to a local Mac gateway? +``` + +Body: + +```text +I am working on CodePilot, an iPhone companion for a Mac app that runs a local token-protected gateway for Codex sessions. I am the maker, so this is related to my own project; no link unless the mods say that is appropriate. + +The SwiftUI side has to represent a few states cleanly: + +- no gateway URL/token configured +- local network URL configured but unreachable +- remote Cloudflare URL configured but gateway down +- token rejected +- gateway healthy but Codex account/session state unavailable +- active turn running +- active turn finished with logs/notifications available + +The current direction is to keep connection setup separate from session state, so the UI does not treat every failure as a generic network error. The app should show a specific recovery step: start gateway, copy current token, check tunnel, rotate token, or retry health check. + +For people building SwiftUI clients around local services: would you model this as one state machine, separate observable models, or typed error states flowing through async calls? I am trying to keep the UI honest without making onboarding feel like a debugger. +``` + +## Draft 6: `r/macapps` Monthly Megathread Comment + +Posting target: `r/macapps` monthly promotion megathread unless account qualifies for main feed. + +Approval status: needs maintainer approval before posting; hold until account has 10 local karma or mods approve. + +Rule notes: +- Use only official distribution links. +- No redirects, referrals, invite links, or shortened URLs. +- Disclose maker relationship. +- Do not use "Free" flair or pricing language for a beta with undecided commercial model. +- Current App Pile PCP format expects pricing and a link; because this run must not imply paid subscription details or post unapproved links, ask moderators before using a beta-feedback exception. + +Moderator note draft: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac + iPhone companion for people running Codex from a Mac they control. + +I saw the PCP format for promotion and the pricing/link requirements. CodePilot is not ready for a pricing announcement, and I do not want to imply paid details or post an unapproved link. + +Would a no-link beta-feedback comment be acceptable in the monthly thread if it clearly says there is no pricing announcement, discloses that I am the maker, and asks only for setup/trust feedback from Mac users? If not, I will hold until there is an official distribution link and approved pricing language. +``` + +Megathread body if approved: + +```text +I am the maker of CodePilot, currently in beta. + +It is a Mac menu bar app plus iPhone companion for people running Codex from a Mac they control. The Mac app tracks local account/usage state and coordinates safe account switching. The local gateway lets the iPhone companion check status, browse threads, upload files, and steer or stop active turns without moving the provider login to the phone. + +The current public-beta iPhone path uses a user-owned Cloudflare Tunnel because the gateway listens on loopback, and the phone still needs the gateway token. The main thing I am looking for right now is setup and trust feedback from Mac users who already work with CLI coding agents. + +I am trying to learn whether the beta setup is understandable and what security/setup explanation Mac users would expect before trying it. +``` + +## Draft 7: `r/OpenAI` Moderator-Approval Discussion + +Posting target: `r/OpenAI` + +Approval status: moderator approval required before posting. Do not include a link unless mods explicitly allow it. + +Moderator note draft: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac + iPhone companion for people running Codex on their own Mac. I saw the rule/guidance against self-promotional direct project links, so I do not want to post a launch link. + +Would a text-only discussion asking Codex users what they would need before trusting an iPhone-to-local-Mac gateway setup be acceptable? I would disclose that I am the maker and avoid pricing or promotional claims. +``` + +Discussion body if approved: + +```text +I am the maker of CodePilot, a beta Mac + iPhone companion for people running Codex on their own Mac. I am not posting a link here; I am looking for product/security feedback from Codex users. + +The beta architecture is: Codex stays on the Mac, a local token-protected gateway exposes narrow session/status/file endpoints, and the current public-beta iPhone path connects through a user-owned Cloudflare Tunnel for remote status, file upload, and turn controls. + +For people who use Codex CLI seriously: what would you need to see before trusting a setup like this? + +- clear source/build instructions? +- documented token storage and rotation? +- gateway endpoint list? +- no remote access by default? +- security review checklist? +- something else? + +I am trying to make the beta setup transparent before inviting broader testers. +``` + +## Draft 8: `r/selfhosted` Moderator Note Only + +Posting target: `r/selfhosted` + +Approval status: hold. Moderator approval and maintainer approval required before any post or comment. Do not post until public docs are ready and the beta is production-ready enough for the community's self-promotion rule. + +Reason for hold: +- CodePilot includes a local gateway and a user-owned tunnel for the current public-beta iPhone path, but it is not primarily a general self-hosted server product. +- Community rules expect promoted apps to be production-ready and documented. +- A project under 3 months old may be introduced only in the current New Project Megathread; confirm project age and the live megathread before any later submission. +- A beta feedback post could read as promotion unless moderators explicitly approve it. + +Moderator note draft: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac + iPhone companion for people running Codex from a Mac they control. + +It includes a token-protected local gateway and uses a user-owned Cloudflare Tunnel for the current public-beta iPhone path, but I am not sure it is a good fit for r/selfhosted because the product is mainly for Codex workflow control rather than general self-hosting. + +Would you prefer that I hold off until public docs and production readiness are stronger? If a text-only architecture/security feedback post would be acceptable later, I would disclose that I am the maker, avoid pricing language, and avoid posting a promotional link unless you approve it. +``` + +## Draft 9: `r/MacOS` Developer Saturday Post + +Posting target: `r/MacOS` + +Approval status: needs maintainer approval before posting. Saturday only from +00:00 through 23:59 UTC; maximum one promotional post per user per week. Do not +post from an automated account. + +Posting gates: +- Explicitly disclose the maker relationship. +- Explain what the app does and how it helps Mac users; do not drop only a link. +- Link only to an approved, accessible, security-ready GitHub repository or + official distribution page. GitHub links are subject to GitHub-Guard scanning. +- Re-check the live policy immediately before posting. + +Title: + +```text +I built a Mac + iPhone companion for checking and steering Codex sessions away from my desk +``` + +No-link body draft: + +```text +I am the maker of CodePilot, a beta Mac menu bar app plus iPhone companion for people who run Codex from a Mac they control. + +The Mac remains the source of truth for Codex auth, project files, account state, and active sessions. The menu bar app shows local account and usage state, while a token-protected loopback gateway gives the iPhone client narrow access to session status, file uploads, notifications, and controls for steering or stopping an active turn. For the current public-beta path, the user connects the phone through a Cloudflare Tunnel they control; the provider login stays on the Mac. + +I am looking for setup and trust feedback, not upvotes. For Mac users who run coding agents locally: which part would make you stop during setup—the gateway token, tunnel, iPhone pairing, or the idea of remote turn control? What security or recovery documentation would you expect before trying the beta? + +I have left out the link in this draft until the public repository or distribution page has passed launch review. If approved at posting time, I will add only the direct official link. +``` + +## Draft 10: `r/TestFlight` Beta Post + +Posting target: `r/TestFlight` + +Approval status: hold until a maintainer approves final posting and a public +TestFlight link has been verified. The placeholder below must never be posted. + +Posting gates: +- The title must be the app name with only an optional short message; do not use + tags such as `[Tester]` or `[Recruiting]`. +- Select the `iOS` post flair. +- Include only the direct Apple TestFlight link. Do not include the repository, + website, redirects, or other external links. +- Keep the body and follow-up comments focused on the TestFlight app. +- Do not repost routine updates; add them as comments on the original post. +- Do not request personal information. Ask testers to use approved feedback + channels and remind them not to share tokens, private logs, or credentials. + +Title: + +```text +CodePilot - iPhone companion for Codex sessions on your Mac +``` + +Body: + +```text +I am the maker of CodePilot. This is a beta iPhone companion for people who already run Codex on a Mac they control. + +The iPhone app connects to CodePilot's token-protected gateway on the Mac. It can show session and account status, browse threads, upload files, receive turn-finished notifications, and steer or stop an active turn. Codex credentials and project files remain on the Mac. For remote access in the current beta, testers use a Cloudflare Tunnel they control. + +I am especially looking for feedback on: + +- whether the Mac-to-iPhone connection setup is understandable +- whether token and tunnel recovery steps are clear +- whether session controls are useful away from the desk +- which setup step would make you abandon the beta + +Please do not send gateway tokens, credentials, private hostnames, private logs, or project files in Reddit messages or comments. Use only sanitized reproduction steps in feedback. + +TestFlight: [APPROVED_PUBLIC_TESTFLIGHT_LINK] +``` + +## Draft 11: `r/GenAiApps` Text-First Beta Feedback Post + +Posting target: `r/GenAiApps` + +Approval status: needs maintainer approval before posting. Use the `iOS` flair +and do not add a link until the public beta URL is verified and approved. + +Rule notes: +- Keep the post focused on a generative-AI app or workflow. +- Self-promotion must provide useful context rather than a low-effort link drop. +- Avoid duplicate promotion and use an appropriate flair. +- If a link is approved later, explain its relevance and verify that it is safe. +- Do not include personal information, private logs, tokens, or credentials. + +Title: + +```text +I built an iPhone companion for Codex sessions running on your Mac - looking for beta workflow feedback +``` + +Body: + +```text +I am the maker of CodePilot. It is a beta Mac + iPhone companion for people who already run Codex on a Mac they control. + +The idea is to leave the coding-agent session, credentials, and project files on the Mac while giving the iPhone a focused view of session status, threads, file uploads, notifications, and controls to steer or stop an active turn. The Mac runs a token-protected local gateway; remote access in the current beta uses a Cloudflare Tunnel controlled by the tester. + +I am trying to learn whether this solves a real generative-AI workflow problem or just moves a terminal-shaped problem onto a smaller screen. The feedback I would value most is: + +- when you would actually check or control a coding-agent session from your phone +- which remote actions feel useful versus risky +- whether the Mac gateway and iPhone connection model is understandable +- what trust or setup concern would stop you from trying the beta + +This is a feedback request, not an upvote request. Please do not share credentials, gateway tokens, private hostnames, private logs, or project files in comments or messages. I will add an approved beta link only when public distribution is ready. +``` + +## Draft 12: `r/github` Self-Promotion Megathread Comment + +Posting target: the current designated `r/github` self-promotion megathread. + +Approval status: hold until a maintainer approves final posting and an +accessible public GitHub repository URL has passed the privacy audit. The +placeholder below must never be posted. + +Rule notes: +- Use the designated self-promotion megathread, not a standalone feed post. +- Include a short description and direct GitHub repository link. +- Add useful stack, feature, or contribution context. +- Disclose the maker relationship and do not request stars or upvotes. +- Re-check that the thread remains the current promotion route before posting. + +```text +Hi, I am the maker of CodePilot, a beta Mac + iPhone companion for people who run Codex from a Mac they control. + +The project has three parts: a Mac menu bar app for local account and usage state, a token-protected local gateway, and a SwiftUI iPhone client for session status, file uploads, notifications, and controls to steer or stop an active turn. The Mac remains the source of truth for Codex credentials, project files, and active sessions. For the current public-beta remote path, testers connect through a Cloudflare Tunnel they control. + +I am sharing the repository for technical and setup feedback, not asking for stars or votes. The feedback I would value most is whether the trust boundary is understandable, whether the setup documentation makes the gateway and tunnel responsibilities clear, and which parts of the repository should be easier to audit or contribute to. + +GitHub: [APPROVED_PUBLIC_GITHUB_REPOSITORY_URL] +``` + +## Draft 13: `r/SideProject` Self-Promotion Thread Comment + +Posting target: the current `r/SideProject` self-promotion thread. + +Approval status: needs maintainer approval before posting. Post manually from an +approved identity; do not use an automated or promotion-only account. + +Rule and community notes: +- The live About page currently lists no community-specific posting rules, so + Reddit-wide authenticity and spam rules still apply. +- Prefer a current thread that explicitly invites self-promotion rather than a + standalone launch post. +- Disclose the maker relationship and ask for specific product feedback. +- Use the no-link version unless a direct public beta URL is separately approved. +- Do not ask for upvotes, stars, follows, direct messages, or personal data. +- Re-check the live About page and target thread immediately before posting. + +```text +Hi, I am the maker of CodePilot. It is a beta Mac + iPhone companion for people who run Codex sessions on a Mac they control. + +I built it around a specific problem: a coding-agent turn can keep running after I leave my desk, but I do not want to move provider credentials or project files to another hosted service. CodePilot leaves those on the Mac. A token-protected local gateway gives the iPhone client narrow access to session status, threads, file uploads, notifications, and controls to steer or stop an active turn. The current public-beta remote path uses a Cloudflare Tunnel controlled by the tester. + +I am looking for blunt feedback on the idea before broader distribution: + +- Is checking or steering a coding-agent session from a phone a real workflow, or just a smaller terminal-shaped distraction? +- Does the Mac gateway plus user-owned tunnel model feel understandable? +- Which part would stop you from trying the beta: setup effort, token handling, remote access, or something else? + +This is a feedback request, not an upvote request. I have left out the beta link until public distribution is approved. Please do not share credentials, gateway tokens, private hostnames, logs, or project files in replies. +``` + +## Draft 14: `r/AI_Agents` Weekly Project Display Comment + +Posting target: the current `r/AI_Agents` weekly Project Display thread. + +Approval status: needs maintainer approval before posting. Hold until the +approved identity has genuine non-promotional participation and its promotion +ratio is safely below the community's one-in-ten guideline. + +Rule notes: +- Use the weekly Project Display thread rather than a standalone project post. +- Provide useful agent-workflow context; do not submit a low-effort link drop. +- Disclose the maker relationship and do not ask for votes, follows, or messages. +- Keep links out of the project description. If a direct beta or repository URL + is separately approved, place it in a reply as required by the live rules. +- Re-check the live About page and current weekly thread immediately before a + maintainer posts manually. + +```text +Hi, I am the maker of CodePilot. It is a beta Mac + iPhone companion for people who run Codex sessions on a Mac they control. + +The agent-workflow problem I am exploring is what should remain possible after you leave the terminal. CodePilot keeps the Codex session, credentials, and project files on the Mac. A token-protected local gateway gives the iPhone client narrow access to session status, threads, file uploads, notifications, and controls to steer or stop an active turn. The current public-beta remote path uses a Cloudflare Tunnel controlled by the tester. + +I would value feedback from people who run coding agents on longer tasks: + +- Which remote actions are genuinely useful: status, steering, stopping, file upload, or none of them? +- Which actions should always require a fresh confirmation on the Mac or phone? +- Does a user-owned gateway and tunnel make the trust boundary clearer, or just make setup harder? +- What audit or recovery information would you expect before connecting a phone to an active agent session? + +This is a workflow and trust feedback request, not an upvote request. I have left out the beta link until public distribution is approved. Please do not share credentials, gateway tokens, private hostnames, logs, or project files in replies. +``` + +## Draft 15: `r/BetaTests` Tester Feedback Post + +Posting target: `r/BetaTests` main feed. + +Approval status: needs maintainer approval before posting. The approved identity +must be at least 24 hours old and have at least 2 combined Reddit karma. Do not +create an account or manufacture activity to meet those thresholds. + +Rule notes: +- Keep the post specifically about beta testing, feedback, and product building. +- Provide enough detail for testers to judge fit; do not make a low-effort link drop. +- Follow the current posting guidance by explaining the product clearly and + asking specific feedback questions. A link is recommended when available, + but this draft must remain link-free until a direct public beta URL is + verified and approved. +- Disclose the maker relationship and do not repeat the same promotion. +- Use the no-link body unless a direct public beta URL is separately verified + and approved. +- Re-check the live About page immediately before a maintainer posts manually. + +Title: + +```text +Looking for setup feedback on CodePilot, an iPhone companion for Codex sessions on a Mac +``` + +Body: + +```text +I am the maker of CodePilot. I am looking for a small number of beta testers who already run Codex on macOS and can give specific setup feedback. + +CodePilot leaves the Codex session, credentials, and project files on the Mac. A token-protected local gateway gives the iPhone companion narrow access to session status, threads, file uploads, notifications, and controls to steer or stop an active turn. For the current public-beta remote path, the tester connects through a Cloudflare Tunnel they control. + +The beta questions I most need answered are: + +- Is the Mac gateway and iPhone pairing flow understandable without live help? +- Is it clear what the gateway token protects and how to recover from a rejected token? +- Does checking or steering a coding-agent turn from a phone solve a real workflow problem? +- Which trust or setup concern would make you stop testing? + +This is a feedback request, not an upvote request. I have left out the beta link until public distribution is approved. Please do not share credentials, gateway tokens, private hostnames, private logs, screenshots containing private project data, or project files in replies. +``` + +## Draft 16: `r/alphaandbetausers` Tester Feedback Post + +Posting target: `r/alphaandbetausers` main feed. + +Approval status: needs maintainer approval before posting. Use the link-free +body unless a direct public beta URL is separately verified and approved. + +Rule and community notes: +- The live About page currently lists no community-specific rules, so + Reddit-wide authenticity and spam rules still apply. +- Recent posts show that explicit iOS and TestFlight tester requests fit the + community, but this is observed practice rather than guaranteed approval. +- Disclose the maker relationship and ask for specific testing feedback. +- Do not promise reciprocal testing, rewards, or other incentives without + separate maintainer approval. +- Do not ask for upvotes or private project data, and do not repeat the post. +- Re-check the live About page and recent removals before a maintainer posts. + +Title: + +```text +Looking for Mac-based Codex users to test an iPhone companion setup +``` + +Body: + +```text +I am the maker of CodePilot. I am looking for a small number of beta testers who already run Codex on macOS and can give specific feedback on a Mac-to-iPhone setup. + +CodePilot keeps the Codex session, credentials, and project files on the Mac. A token-protected local gateway gives the iPhone companion narrow access to session status, threads, file uploads, notifications, and controls to steer or stop an active turn. For remote access in the current beta, testers use a Cloudflare Tunnel they control. + +The questions I most need answered are: + +- Can you complete the Mac gateway and iPhone connection flow without live help? +- Is it clear what the gateway token protects and how to recover from a rejected connection? +- Does checking or steering a coding-agent turn from a phone solve a real workflow problem? +- Which setup or trust concern would make you stop testing? + +This is a feedback request, not an upvote request. I have left out the beta link until public distribution is approved. Please do not share credentials, gateway tokens, private hostnames, private logs, screenshots containing private project data, or project files in replies. +``` + +## Draft 17: `r/indiehackers` One-Time Product Validation Post + +Posting target: `r/indiehackers` main feed using the current designated +self-promotion flair. + +Approval status: needs maintainer approval before posting. Hold until the live +flair requirement is confirmed and the approved identity has genuine, +non-promotional participation in the community. + +Rule notes: +- The community permits one self-promotional product post for feedback and + critique, not advertising. +- The written rule says `SHOW IH`, while the live flair list currently shows + `Self Promotion`; confirm the correct option immediately before posting. +- Do not use fake Q&A framing, repeat the post, make revenue claims, or ask for + votes or artificial engagement. +- Keep the body link-free unless a public beta URL is separately verified and + approved. + +Title: + +```text +Validating CodePilot: a phone companion for coding agents running on a Mac +``` + +Body: + +```text +I am the maker of CodePilot. I am validating a beta Mac + iPhone companion for people who run Codex sessions on a Mac they control. + +The constraint behind it is that the coding-agent session, credentials, and project files stay on the Mac. CodePilot adds a Mac menu bar app, a token-protected local gateway, and an iPhone client with narrow controls for session status, threads, file uploads, notifications, steering, and stopping an active turn. Remote access in the current beta uses a Cloudflare Tunnel controlled by the tester. + +I am trying to separate a real away-from-desk workflow from a feature that only sounds convenient. I would value critique on three points: + +- When, if ever, would you check or steer a coding-agent turn from a phone? +- Does keeping the session on the Mac make the trust boundary clearer, or does the gateway and tunnel setup outweigh that benefit? +- What is the smallest useful beta: read-only status and notifications, or active steering and stop controls? + +This is product validation, not an upvote request. I have left out the beta link until public distribution is approved. Please do not share credentials, gateway tokens, private hostnames, logs, screenshots containing private project data, or project files in replies. +``` + +## Draft 18: `r/macosprogramming` Moderator-First Technical Discussion + +Posting target: `r/macosprogramming`, only after moderator permission. + +Approval status: moderator and maintainer approval required. CodePilot is +source-available under a noncommercial license, not OSI open source, so do not +use the community's open-source promotion exception. + +Moderator note draft: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac menu bar app with a local gateway and an iPhone companion for people running Codex on macOS. + +I saw that non-open-source app promotion requires prior permission. CodePilot's repository is source-available under a noncommercial license, so I am not assuming the open-source exception applies. + +Would a text-first technical discussion be acceptable if it focuses on the macOS architecture: keeping credentials and project files on the Mac, exposing a token-protected loopback gateway, coordinating menu bar state with active coding-agent turns, and asking for feedback on the security and lifecycle design? I would disclose that I am the maker, omit pricing and promotional claims, include no link unless you approve one, and keep the discussion specific to macOS development. +``` + +Discussion body if moderators approve; a maintainer should review and rewrite it +manually before posting to ensure it reflects the current implementation and +adds concrete developer value: + +```text +I am the maker of CodePilot, and I would value macOS architecture feedback on a beta menu bar app and local gateway for controlling coding-agent sessions from an iPhone. + +The Mac remains the source of truth for the Codex session, credentials, account state, and project files. The menu bar app coordinates account and usage state, while a token-protected loopback HTTP service exposes a narrow API for thread status, file uploads, notifications, steering, and stopping an active turn. Optional remote access is through a Cloudflare Tunnel configured by the tester. + +The design questions I am working through are: + +- Which gateway lifecycle and failure states should the menu bar app surface directly? +- What macOS-native confirmation or permission boundary would you expect before allowing remote steering or stop controls? +- Is a loopback-only service plus user-owned tunnel a comprehensible trust boundary for a Mac utility, or should the first beta remain local-network only? +- Which logs and diagnostics are useful for setup recovery without exposing tokens, hostnames, or project data? + +I am looking for technical critique rather than installs or votes. I have omitted links while the beta distribution and public repository are still under approval. +``` + +## Draft 19: `r/LLMDevs` Technical Project Discussion + +Posting target: `r/LLMDevs` main feed. + +Approval status: needs maintainer approval before posting. Hold until an +accessible public repository URL has passed the privacy audit and a maintainer +confirms that the current noncommercial-license exception covers the PolyForm +Noncommercial License. + +Rule notes: +- Disclose the maker relationship in the opening sentence. +- Describe CodePilot as source-available under a noncommercial license; do not + call it open source. +- Include concrete LLM-agent architecture and trust questions so the post adds + technical value. +- Do not use fake question framing, obscure the affiliation, make commercial + claims, or ask for installs, votes, or private messages. +- Replace the repository placeholder only with a separately approved, + accessible, privacy-audited public URL. +- Re-check the live About page and self-promotion clarification immediately + before a maintainer posts manually. + +Title: + +```text +Architecture feedback: keeping Codex sessions on a Mac while exposing narrow iPhone controls +``` + +Body: + +```text +I am the maker of CodePilot, a beta Mac menu bar app, local gateway, and iPhone companion for Codex users. The code is source-available under the PolyForm Noncommercial License; it is not OSI open source. + +The design keeps the Codex session, provider credentials, and project files on a Mac controlled by the user. A token-protected loopback gateway exposes a narrow API for session status, threads, file uploads, notifications, and controls to steer or stop an active turn. For the current public-beta remote path, the tester connects through a Cloudflare Tunnel they control. + +I would value technical criticism of three boundaries: + +- Is a loopback gateway plus a user-owned tunnel a clear trust model for remote agent controls, or is it too much setup for the benefit? +- Which actions should require fresh confirmation, stronger authentication, or remain read-only? +- What audit events and recovery information would help diagnose failures without leaking prompts, tokens, hostnames, or project data? + +Repository: [APPROVED PUBLIC REPOSITORY URL] + +I am looking for architecture and security feedback, not votes or promotional amplification. Please do not share credentials, gateway tokens, private hostnames, logs, or project files in replies. +``` + +## Draft 20: `r/apple` Developer Sunday Self-Post + +Posting target: `r/apple`, only during the community's Sunday window in +California time. + +Approval status: hold until an approved `codepilotios` identity already has at +least 5 unrelated posts or comments in `r/apple` during the previous month and +self-promotion remains at or below 10% of its community activity. Do not create +an account or manufacture participation to meet this gate. + +Posting gates: +- Use a substantive text self-post, not a direct link post. +- Include one direct official beta, App Store, or privacy-audited repository URL; + the placeholder below must never be posted. +- Disclose the maker relationship in the opening sentence. +- Explain the Apple-platform use case and invite specific beta feedback rather + than votes, follows, or messages. +- A maintainer must confirm eligibility, Sunday timing, the exact copy, and the + official URL immediately before posting manually. + +Title: + +```text +I built a Mac + iPhone companion for checking and steering Codex sessions away from my desk +``` + +Body: + +```text +I am the maker of CodePilot, a beta Mac menu bar app and iPhone companion for people who run Codex on a Mac they control. + +CodePilot keeps the coding-agent session, credentials, and project files on the Mac. A token-protected loopback gateway gives the iPhone app narrow access to session status, threads, file uploads, notifications, and controls for steering or stopping an active turn. For remote access in the current beta, the tester uses a Cloudflare Tunnel they control. + +I am looking for specific Apple-platform beta feedback: + +- Is the handoff from Mac setup to iPhone pairing understandable without live help? +- Which away-from-desk action is actually useful: status, notifications, steering, stopping, or file upload? +- What security or recovery explanation would you expect before connecting an iPhone to a local Mac gateway? +- Which setup step would make you abandon the beta? + +This is a feedback request, not an upvote request. Please do not share credentials, gateway tokens, private hostnames, logs, screenshots containing private project data, or project files in replies. + +Official beta or repository link: [APPROVED_DIRECT_OFFICIAL_URL] +``` + +## Draft 21: `r/ChatGPTPro` Technical Power-User Discussion + +Posting target: `r/ChatGPTPro` main feed. + +Approval status: hold until the approved `codepilotios` identity has genuine +non-promotional technical participation in the community, self-promotion would +remain at or below 10% of its activity there, and moderators approve the exact +maker-authored discussion. Do not create activity solely to satisfy this gate. + +Rule notes: +- Keep the post about an advanced Codex workflow and its trust boundaries, not a + generic app announcement or tester request. +- Disclose the maker relationship in the first sentence. +- Include no product, repository, TestFlight, signup, or direct-message link. +- Do not ask for installs, votes, follows, or private outreach. +- A maintainer must re-check the live rules and recent removals, send any + moderator note, approve the exact copy, and post manually. + +Moderator note: + +```text +Hi mods, I am the maker of CodePilot, a beta Mac + iPhone companion for people who run Codex on a Mac they control. + +I understand that r/ChatGPTPro is for advanced technical workflows and that disclosed self-promotion must stay within the one-in-ten limit and provide clear community value. Would a link-free technical post about the trust and control boundaries of remotely monitoring and steering a local Codex session be acceptable if I disclose my affiliation and ask for architecture criticism rather than testers? + +I will not post it unless you approve the format, and I will not include a product, signup, repository, or beta link. +``` + +Title: + +```text +Where should the trust boundary sit when steering a coding agent away from the workstation? +``` + +Body: + +```text +I am the maker of CodePilot, a beta Mac + iPhone companion for people who run Codex on a Mac they control. + +The workflow I am testing keeps the Codex session, provider credentials, and project files on the Mac. A token-protected loopback gateway exposes only a narrow set of remote actions: read session status, view threads, receive notifications, upload a file, and steer or stop an active turn. The current remote path uses a Cloudflare Tunnel controlled by the tester. + +The hard product question is not whether remote control is technically possible; it is which controls should be available without weakening the workstation's trust boundary. I would value power-user feedback on three choices: + +- Which away-from-desk actions should remain read-only, require fresh confirmation, or never be exposed remotely? +- Is a user-owned tunnel plus a loopback gateway understandable enough to operate safely, or does the setup burden erase the benefit? +- Which audit and recovery details would help diagnose a failure without recording prompts, tokens, private hostnames, or project contents? + +This is an architecture and workflow question, not an install or upvote request. Please do not share credentials, gateway tokens, private logs, hostnames, screenshots, or project files in replies. +``` + +## Hacker News / Show HN Outline + +Approval status: hold. HN is temporarily restricting Show HN submissions to +people who have first become genuine contributors. Do not create an account or +manufacture activity for this launch. A maintainer may use this outline only if +an existing approved public identity is eligible and the beta is directly +usable. + +Do not paste this as-is. HN guidelines ask users not to post generated or +AI-edited comments. A maintainer should rewrite manually if posting. + +Possible title: + +```text +Show HN: CodePilot - an iPhone companion for running Codex sessions from your Mac +``` + +Human rewrite outline: +- One sentence: CodePilot is a Mac menu bar app, local gateway, and iPhone companion for Codex users. +- Explain the personal problem: wanting to monitor/steer a long-running Codex session away from the desk without moving credentials to a hosted service. +- Explain the architecture: Codex remains on the Mac; the current public-beta iPhone path reaches the token-protected, loopback-only gateway through a user-owned Cloudflare Tunnel. +- Be explicit that this is beta and feedback is requested on setup/security clarity. +- Do not ask for upvotes. +- Be present to answer technical questions. +- Only post when there is a public URL that lets people actually try it. + +## Product Hunt Draft Inputs + +Hold until a maintainer approves launch assets and current beta status. Do not fill pricing or promo fields without approval. + +Name: + +```text +CodePilot +``` + +Tagline draft: + +```text +iPhone companion for Codex sessions on your Mac +``` + +Description draft: + +```text +CodePilot connects a Mac menu bar app, local gateway, and iPhone companion so Codex users can check account/usage state, continue sessions, upload files, and steer or stop active turns from a Mac they control. Currently beta-focused; feedback wanted on setup, trust, and remote workflow clarity. +``` + +First comment outline: +- I am the maker. +- Built because coding-agent sessions live on the Mac, but users sometimes need status/control away from the desk. +- Explain the three pieces: Mac app, gateway, iPhone app. +- Explain security posture briefly: token-protected loopback gateway, user-owned tunnel for the current public-beta iPhone path, and no sharing of tokens or private logs. +- Ask for feedback, not upvotes. +- Avoid pricing and subscription language. + +## Feedback Tracking Template + +For each public reply after approved posting: + +```text +Source: +Link: +Type: setup | trust/security | feature | bug | positioning | pricing-question | other +Summary: +Action: +GitHub issue needed: yes/no +Escalation needed: yes/no +``` + +## Escalation Status + +An escalation note was created at +`ops/agents/escalations/community-drafts.md`. Draft preparation is complete, but +all public posting remains blocked on maintainer approval. The recommended first +placement remains the link-free `r/GenAiApps` draft with `iOS` flair. The +`r/ChatGPTCoding` self-promotion-thread draft is also eligible for maintainer +review once the thread and `codepilotios` account-karma eligibility are checked; +main-feed promotion remains out of scope. The `r/TestFlight` draft additionally +requires a verified public TestFlight link. The +`r/BetaTests` draft requires an approved identity that meets the community's +24-hour account-age and 2-karma eligibility gates. The `r/alphaandbetausers` +draft has no visible community-specific eligibility threshold, but still needs +maintainer approval and a live-rule re-check. `r/BetaTestersNeeded` remains held +because its approved-contributor, mandatory-perk, and signup-link gates require +decisions and external account actions outside this run. +The new `r/indiehackers` draft is a held, one-time validation option pending +flair confirmation and genuine participation. The new `r/macosprogramming` +technical draft is moderator-first because CodePilot's source-available license +does not qualify for that community's open-source exception. Hacker News / Show +HN is also held while its temporary genuine-contributor restriction remains; +this run did not create an account or manufacture participation. +The new `r/LLMDevs` technical draft is held until a maintainer confirms that +the live noncommercial-license exception covers the PolyForm Noncommercial +License and approves an accessible, privacy-audited repository URL. +The new `r/apple` Developer Sunday draft is held until the approved identity +already meets the community's organic-participation and one-in-ten promotion +gates and a maintainer approves the timing, exact copy, and direct official URL. +The new `r/ChatGPTPro` technical draft is held until the approved identity has +genuine non-promotional participation, remains within the community's +one-in-ten self-promotion limit, and a maintainer obtains moderator approval for +the exact link-free copy. diff --git a/ops/agents/escalations/community-drafts.md b/ops/agents/escalations/community-drafts.md new file mode 100644 index 00000000..cd99cae7 --- /dev/null +++ b/ops/agents/escalations/community-drafts.md @@ -0,0 +1,105 @@ +# Community Drafts Escalation + +Status: maintainer action required before any public posting. + +- Review and approve the proposed first placement: the link-free `r/GenAiApps` + draft with `iOS` flair. `r/ChatGPTCoding` is currently restricted to approved + contributors; if `codepilotios` is already eligible, maker-authored promotion + must use its current self-promotion thread and remains subject to account-karma + filtering. Do not request contributor status solely for this launch run. +- Confirm that the `codepilotios` identity is approved and eligible under the + target community's account-age, karma, and participation rules. Do not create + an account solely to satisfy this request. +- Do not request `r/ChatGPTCoding` sponsorship solely for this launch run. + Re-check that the currently visible self-promotion thread remains open, + confirm that `codepilotios` can comment without an account-karma removal or + manual-review hold, and approve the exact comment before a human posts it. +- For `r/TestFlight`, provide or approve a verified public Apple TestFlight link; + the draft must contain no other link. +- For `r/BetaTests`, approve the no-link tester-feedback draft and confirm that + the `codepilotios` identity is at least 24 hours old with at least 2 combined + Reddit karma. The community currently permits product beta posts without + moderator pre-approval, but final maintainer approval is still required. Its + current posting guidance asks for a clear product explanation and specific + feedback questions; the prepared draft includes both. Add a link only after a + direct public beta URL is verified and approved. +- For `r/alphaandbetausers`, approve the prepared link-free tester-feedback + draft before a human posts it. The live About page currently shows no + community-specific rules, but the rules and recent removals must be checked + again immediately before posting. Do not add reciprocal-testing promises, + rewards, or an unapproved beta link. +- For `r/iOSProgramming`, confirm Saturday timing, the identity's current + participation and account eligibility, and that its once-per-year app + allowance is unused. Approve the revised technical draft with all three + labeled sections—Tech Stack, Development Challenge, and AI Disclosure—kept + intact; current automated moderation removes posts missing any section. +- Hold `r/BetaTestersNeeded`. It is restricted to approved contributors and + requires a tester perk in the title and body plus a signup/test link. Do not + request approval, invent a perk, imply paid-tier value, or add an unverified + link for this placement. +- Do not cross-post the beta recruitment to `r/appledevelopers`, which directs + TestFlight apps to `r/TestFlight`. Do not use the `r/iosapps` main feed or + App Shelf: its current rules prohibit generative-AI and AI-wrapper apps and + direct them to `r/GenAiApps`. +- Do not use `r/iOSBeta` for CodePilot recruitment. Current automated removals + prohibit posts about third-party apps in beta or TestFlight; use + `r/TestFlight` only after its link and maintainer approval gates are met. +- Do not use `r/ShowMeYourApps`: although it accepts mobile-app promotion, its + live rules explicitly prohibit AI content. Do not reframe CodePilot to bypass + that rule or contact moderators solely to seek an exception. +- `r/GenAiApps` is a text-first alternative whose rules allow contextual, + valuable self-promotion. Approve the prepared copy and `iOS` flair before a + human posts it; do not add a beta link until that URL is verified and approved. +- For `r/AI_Agents`, use only the current weekly Project Display thread after the + approved identity has genuine participation and remains safely below the + community's one-in-ten self-promotion guideline. Approve the no-link draft; + any later approved link belongs in a reply rather than the project description. +- Do not use `r/iPhoneApps` for a standalone launch post. Its Developer flair was + removed on 2026-07-16, and maker mentions now require genuine participation, + contextual value, an App Store listing, and approved status/cost details. +- Hold `r/indiehackers` until a maintainer confirms whether the required live + flair is `SHOW IH` or `Self Promotion` and the approved identity has genuine + non-promotional participation. Approve the one-time, link-free validation + draft before a human posts it; do not make revenue claims or manufacture + engagement. +- Hold Hacker News / Show HN. HN is temporarily restricting Show HN submissions + to genuine contributors. Do not create an account or manufacture activity for + this launch. Reconsider only if an existing approved public identity is + eligible, the beta is directly usable, and a maintainer manually rewrites the + prepared outline. +- Hold `r/apple` unless the approved identity already has at least 5 unrelated + contributions there during the previous month and remains at or below the + community's one-in-ten self-promotion ratio. Developer promotion is limited + to substantive self-posts on Sunday in California time and requires a direct + link. Approve the exact copy, timing, and official URL before a maintainer + posts manually; do not manufacture participation to qualify. +- Treat `r/macosprogramming` as moderator-first. CodePilot is source-available + under a noncommercial license, not OSI open source, so its open-source posting + exception must not be assumed. A maintainer must approve and manually send the + prepared moderator note, then review/rewrite any technical discussion before + posting. +- Hold `r/vibecoding`: its developer-tool approval flow requires a public X + community post and moderator DM. That external account action is outside this + agent's authority and should not be performed solely for promotion. +- For `r/github`, approve an accessible, privacy-audited public repository URL + before using the prepared self-promotion megathread comment. Do not post the + placeholder or use a standalone feed post. +- For `r/LLMDevs`, confirm that its live noncommercial-license exception covers + the PolyForm Noncommercial License, then approve the exact technical draft + and an accessible, privacy-audited public repository URL. Describe CodePilot + as source-available, not open source, and do not use disguised discussion + framing. +- For `r/SideProject`, approve the prepared no-link comment and have a human use + the current self-promotion thread. Do not use a standalone launch post or a + promotion-only account; re-check the live About page and thread first. +- If choosing `r/codex`, `r/OpenAI`, `r/macapps`, or another moderator-first + target, send the prepared modmail manually and wait for approval. +- Hold `r/ChatGPTPro` until the approved identity has genuine non-promotional + technical participation and a CodePilot post would remain at or below 10% of + its community activity. A maintainer must re-check recent enforcement, + approve and manually send the prepared moderator note, then approve and post + the exact link-free technical discussion. Do not manufacture participation or + use the community as a tester-recruitment feed. + +No post, comment, profile change, account action, or moderator message was made +by the community-drafts agent. diff --git a/ops/agents/escalations/presence-maintenance.md b/ops/agents/escalations/presence-maintenance.md index 1f6b78f6..775c502e 100644 --- a/ops/agents/escalations/presence-maintenance.md +++ b/ops/agents/escalations/presence-maintenance.md @@ -1,9 +1,11 @@ # Presence Maintenance Escalation -Approval needed before public publishing: +Approval status: approved by maintainer on 2026-07-06. -- Confirm beta privacy copy in `docs/PRIVACY.md`. -- Confirm public positioning in `README.md`, `docs/index.md`, and `docs/FAQ.md`. -- Review `docs/APP_STORE_METADATA_DRAFT.md` before any TestFlight/App Store metadata is entered publicly. -- Enable or confirm GitHub Pages source for the repository, preferably the `docs/` folder. -- Approve sanitized screenshot capture before screenshots are committed or used in App Store/TestFlight metadata. +The following public-publishing decisions are approved: + +- Beta privacy copy in `docs/PRIVACY.md` once that tracked file exists. +- Public positioning in `README.md`, `docs/index.md`, and `docs/FAQ.md`. +- TestFlight/App Store metadata from `docs/APP_STORE_METADATA_DRAFT.md`. +- GitHub Pages source for the repository, preferably the `docs/` folder. +- Sanitized screenshot capture before screenshots are committed or used in App Store/TestFlight metadata. diff --git a/ops/agents/escalations/security-scan.md b/ops/agents/escalations/security-scan.md index 2eb05a5e..5ff2158a 100644 --- a/ops/agents/escalations/security-scan.md +++ b/ops/agents/escalations/security-scan.md @@ -1,18 +1,20 @@ # CodePilot Security Scan Escalation -Maintainer intervention is needed before public launch for these product-boundary decisions: +Maintainer decision status: approved by maintainer on 2026-07-06. + +Maintainer intervention was requested before public launch for these product-boundary decisions: 1. Authenticated arbitrary file download remains enabled. - Surface: `gateway/codex_phone_gateway.py` exposes `/api/files/download?path=...`. - Current behavior: any client with the gateway bearer token can request any absolute file path readable by the gateway process. - Risk: a leaked or phished gateway token becomes direct local file disclosure, independent of Codex approval/sandbox controls. - - Decision needed: define the allowed file scope for iPhone previews, such as uploaded files, explicit per-thread workspace roots, or short-lived file-preview grants. + - Decision: approved to proceed with the proposed hardening direction. Keep the feature, but narrow the allowed scope before public launch to uploaded files, explicit per-thread workspace roots, or short-lived file-preview grants. 2. Localhost proxy sessions are bearerless capability URLs. - Surface: `POST /api/local-web/sessions` requires the bearer token, but the returned `/api/local-web//...` URL is fetched without bearer auth. - Current behavior: the random session id gates access for the session lifetime. - Risk: anyone who obtains a live session URL can proxy GET requests to the selected loopback port through the public gateway until expiry. - - Decision needed: decide whether this is acceptable for WebView compatibility, should have a shorter lifetime, or should move to an authenticated browser/proxy design. + - Decision: approved to proceed with the proposed hardening direction. Keep WebView compatibility, but shorten and constrain capability sessions before public launch unless an authenticated browser/proxy design is ready. Local hardening already applied in this branch: diff --git a/scripts/build-app.sh b/scripts/build-app.sh index 66b25877..cf2b73e1 100755 --- a/scripts/build-app.sh +++ b/scripts/build-app.sh @@ -12,7 +12,7 @@ cd "$ROOT" swift build -c release rm -rf "$APP" -mkdir -p "$MACOS" "$RESOURCES/scripts" "$FRAMEWORKS" +mkdir -p "$MACOS" "$RESOURCES/scripts" "$RESOURCES/gateway" "$FRAMEWORKS" cp "$ROOT/.build/release/CodexAccountSwitcher" "$MACOS/CodePilot" if [[ -d "$ROOT/.build/arm64-apple-macosx/release/LiveKitWebRTC.framework" ]]; then cp -R "$ROOT/.build/arm64-apple-macosx/release/LiveKitWebRTC.framework" "$FRAMEWORKS/" @@ -20,6 +20,7 @@ if [[ -d "$ROOT/.build/arm64-apple-macosx/release/LiveKitWebRTC.framework" ]]; t fi cp "$ROOT/scripts/"*.sh "$RESOURCES/scripts/" cp "$ROOT/scripts/"*.py "$RESOURCES/scripts/" 2>/dev/null || true +cp "$ROOT/gateway/"*.py "$RESOURCES/gateway/" chmod +x "$RESOURCES/scripts/"*.sh cat > "$CONTENTS/Info.plist" <<'PLIST' diff --git a/scripts/codepilot-agent-runner.sh b/scripts/codepilot-agent-runner.sh index b6504e52..f60a5420 100755 --- a/scripts/codepilot-agent-runner.sh +++ b/scripts/codepilot-agent-runner.sh @@ -10,6 +10,7 @@ WORKTREE_ROOT="$STATE_DIR/worktrees" THREAD_ID_FILE="$STATE_DIR/thread-id" CODEX_BIN="${CODEPILOT_CODEX_BIN:-codex}" CODEX_MODEL="${CODEPILOT_AGENT_MODEL:-}" +AGENT_TIMEOUT_SECONDS="${CODEPILOT_AGENT_TIMEOUT_SECONDS:-7200}" GUARD_BIN="$ROOT/scripts/agent-guard-bin" PUBLIC_AUTONOMY="${CODEPILOT_AGENT_PUBLIC_AUTONOMY:-launch}" @@ -71,6 +72,17 @@ if [[ -d "$WORKTREE/.git" || -f "$WORKTREE/.git" ]]; then cd "$WORKTREE" fi +git fetch --quiet origin main 2>/dev/null || true +if git diff --quiet && git diff --cached --quiet; then + if git merge-base --is-ancestor HEAD origin/main 2>/dev/null; then + git merge --ff-only --quiet origin/main + else + echo "Agent worktree has commits not on origin/main; leaving branch as-is." + fi +else + echo "Agent worktree has local changes; skipping origin/main refresh." +fi + REAL_GIT="$(command -v git)" REAL_GH="$(command -v gh 2>/dev/null || true)" export CODEPILOT_AGENT_REAL_GIT="$REAL_GIT" @@ -137,15 +149,34 @@ escalation only when maintainer intervention is genuinely required. EOF ) +prompt_file="$(mktemp "${TMPDIR:-/tmp}/codepilot-agent-prompt.XXXXXX")" +trap 'rm -f "$prompt_file" 2>/dev/null || true; rm -rf "$LOCK_DIR" 2>/dev/null || true' EXIT + { printf '%s\n\n' "$PUBLIC_WRITE_POLICY" cat "$PROMPT" -} | "$CODEX_BIN" exec \ +} > "$prompt_file" + +"$CODEX_BIN" exec \ --cd "$PWD" \ "${model_args[@]}" \ --config "model_reasoning_effort=\"$REASONING_EFFORT\"" \ --sandbox danger-full-access \ - - + - < "$prompt_file" & +codex_pid="$!" +deadline=$((SECONDS + AGENT_TIMEOUT_SECONDS)) +while kill -0 "$codex_pid" 2>/dev/null; do + if (( SECONDS >= deadline )); then + echo "CodePilot agent timed out after ${AGENT_TIMEOUT_SECONDS}s: $JOB" >&2 + kill -TERM "$codex_pid" 2>/dev/null || true + sleep 10 + kill -KILL "$codex_pid" 2>/dev/null || true + wait "$codex_pid" 2>/dev/null || true + exit 124 + fi + sleep 5 +done +wait "$codex_pid" fi diff --git a/scripts/install-phone-gateway-agent.sh b/scripts/install-phone-gateway-agent.sh index da866941..b6350bb3 100755 --- a/scripts/install-phone-gateway-agent.sh +++ b/scripts/install-phone-gateway-agent.sh @@ -6,7 +6,15 @@ if [[ "${1:-}" == "--force" ]]; then FORCE_RESTART="1" fi -ROOT="$(cd "$(dirname "$0")/.." && pwd)" +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +if [[ "$(basename "$ROOT")" == "Resources" && "$(basename "$(dirname "$ROOT")")" == "Contents" ]]; then + APP_BUNDLE="$(dirname "$(dirname "$ROOT")")" + REPO_ROOT="$(cd "$APP_BUNDLE/../../.." && pwd)" + if [[ -f "$REPO_ROOT/gateway/codex_phone_gateway.py" ]]; then + ROOT="$REPO_ROOT" + fi +fi LABEL="${CODEPILOT_GATEWAY_LAUNCHD_LABEL:-io.codepilot.phone-gateway}" PLIST="$HOME/Library/LaunchAgents/$LABEL.plist" mkdir -p "$HOME/Library/LaunchAgents" "$HOME/Library/Logs"