2026-08-23 · Claude Code (Mia) · status: proposal — nothing built until Byron's go
Live app: https://mentor.arnao.ai · Canonical state: [file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/CANONICAL-STATE.md](file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/CANONICAL-STATE.md)
A new server-verified role, pm (user-facing: Product Manager), lets a chosen mentee — no programming skill required — run the product: triage the incoming feedback/PR queue, email the user base, schedule Google Meet sessions, propose and prioritize features, watch an AI worker build them, test the preview, and drive the rollout (with Byron's 30-second tap gating each production promote in v1) — all inside guardrails that make it impossible for them to spend past a hard monthly cap, touch auth/roles/secrets, or steer the product off its mission. The expensive model (Opus 4.8) is their thinking partner; a cheap model (GLM via Z.ai's $10/mo coding plan) does the actual building. Total worst-case cost: ≤ $37/month, under the $50 ceiling with headroom.
Why this is cheap to build: Mentor already has ~70% of the chassis. Server-verified Google-email roles (meta/roles.json), an admin Controller with a Backlog & Releases queue (feedback auto-imports as MEN-NNN items; "Create PR" bundles a release brief), a working Gmail sender, per-user spend caps, and a global cost ledger are all live today. The PM role is mostly scoping existing power down, not building new power up.
| Capability | PM | How it's enforced |
|---|---|---|
| Review incoming feedback / feature requests / "PRs" | ✅ approve · decline · prioritize · bundle releases | backlog.js gate widens from admin-only to admin-or-pm |
| See users (names, activity, tier, last-active) | ✅ read-only | ?list / ?activity accept viewer.pm |
| Invite new users | ✅ within existing 20/day cap | existing invite action, gate widened |
| Email the whole user group | ✅ 4 blasts/month, charter-linted, BCC Byron | new broadcast action (§4) |
| Schedule Google Meet sessions | ✅ | new meet action → gog calendar create --with-meet (§4) |
| Plan features with an AI copilot | ✅ Opus 4.8, hard $15/mo budget | new pmplan AI mode charged to PM's own rec.cap (§5) |
| Trigger builds | ✅ via "Create PR" → GLM worker builds to a preview URL | executor on Mia, never deploys prod (§6) |
| Promote a build to production | 🔶 every promote needs Byron's 30-sec tap in v1 (graduation path defined) · PM-alone rollback always allowed | promote broker (§6) |
| Feature flags / A/B tests | ✅ create flag, set %, read results | new flags engine (§7) |
| Edit roles, budgets, tiers, config | ❌ | roles/config/tier/setcap/settier stay admin-only |
| Disable/delete a user | ❌ (can propose → needs-Byron) | actions stay admin-only |
| Touch secrets, env vars, auth code | ❌ | protected-path list + executor sandbox |
| Spend past cap | ❌ server-enforced, not honor-system | same rec.cap machinery that already 429s users today |
The "sell drugs" case: a Product Charter (§8) is the constitution. The copilot won't plan against it, the broadcast linter won't send against it, and any charter-flagged item lands in a needs-Byron queue instead of executing. The PM has autonomy inside the charter, a request path outside it — never silent power.
The codebase audit found a role string grants nothing unless wired in exactly four places — miss one and pm silently no-ops:
expandRoles() — _store.js:373 (pm expands to just pm)roleFromReq() two-vocabulary collapse — _store.js:324 (pm maps to mentor-level for legacy checks, and never to admin)viewerFromReq() — _store.js:461 (adds a viewer.pm boolean alongside admin/orchestrator)ROLE_ACTIONS + per-action gates — user.js:308 (new second-stage pm_allowed check per §2's table)Client side: the hardcoded 3-entry role modal (index.html:930) and loginGo() mapping gain a 4th entry → a PM console view: the existing Controller, minus the Cost-config/Users-admin controls, plus the new Comms / Copilot / Flags tabs. Granting the role = one line in meta/roles.json via the existing runtime roles action — no redeploy, revocable in seconds.
Broadcast — new admin-or-pm action broadcast {subject, body, audience}:
?list summary (email, name, test flag — test accounts excluded). User cap is 300 by design; that's the natural blast ceiling.gemini-2.5-flash-lite: bans, tone, dead links, claims about features that don't exist) · unsubscribe/opt-out line mandatory (CAN-SPAM basics) · sends via the proven store.sendGmail path, throttled ~1/sec.needs-byron.mentor@arnao.ai mailbox or Gmail alias with its own refresh token) — protects byron.arnao@gmail.com from spam-classification at 300 recipients and stops the PM's output reading as Byron personally. Byron stays BCC'd.segments.json is names-of-registered-users only, so neither the PM nor a compromised PM account can blast arbitrary external addresses.Meetings — new action meet {title, when, durationMin, audience}:
gog calendar create primary --with-meet --attendees=… works with Byron's already-authorized byron.arnao@gmail.com OAuth (calendar scope granted, gog v0.17.0 in the gia container). Zero new auth.meta/meet-queue.json; a Gia watcher cron (same pattern as the RAI refresh watcher) picks it up within 5 min, runs gog, writes the Meet link back; PM console shows it and can include it in a broadcast. Guardrails: 8 events/month; attendees re-validated against the user list; the watcher strict-schema-validates every field and invokes gog via an argv array, never a string-built shell command (no shell-injection path from attendee/title text).meta/segments.json (e.g. "beta-circle", "new-mentees") the PM edits in-console, used as the audience for both blasts and meetings. Simpler, no new Google surface.New AI mode pmplan in ai.js (mode #19, alongside the existing 18):
claude-opus-4-8 — already allowlisted at $5/$25 per Mtok. This is the "form their plans, interactive chat" partner. (Fable 5 was considered; it's the priciest tier and the delta doesn't matter for PM planning chat. Option: pin the monthly product review — one synthesis call/month — to Fable, ~$1/mo.)MEN-NNN backlog item on request.rec.cap + settleSpend → 429 cap_reached) — the same code that protects the app today, no new enforcement to trust. At 80% burn the mode downgrades to gemini-2.5-flash ($0.30/$2.50) — visibly, with a console notice, never silently. Honest throughput math (Fable pass corrected the first estimate): with injected context at 15–30k input tokens/turn, $15 buys roughly 40–100 full Opus exchanges/month, not 200+. Mitigation: context is tiered — the full backlog/activity snapshot loads once per session, follow-up turns carry only the delta — targeting the high end of that range.The PM's "Create PR" already produces a release brief and Telegram-pings ops. Today a human agent picks it up. The new piece is an executor daemon on Mia (launchd, like Security Sentinel):
/api/backlog for queued releases (admin token, existing pickup contract).z-ai/glm-5.2:free on OpenRouter — $0, ~200 req/day.--prod), posts the preview URL + a server-computed deterministic diff (git diff --stat + changed-file list — never a model-written summary, since a compromised model would summarize its own backdoor honestly-sounding), marks picked_up.Executor security (the prompt-injection chain, taken seriously). Feedback items are attacker-authored text that flows into a coding model — so the pipeline assumes a hostile brief:
ADMIN_PW, FB_SECRET, Gmail creds, provider API keys, or the backlog admin token. Agent network egress is allowlisted (Z.ai, npm, Vercel).BLOB_READ_WRITE_TOKEN or prod provider keys. GLM-authored code never executes against production data pre-review. (Vercel scopes env per-environment; this is config, not new infra — but it's a P4 precondition, verified before the first real build.)node --check, never-break-Start-now smoke test) runs as hard scripted checks on the preview — the Promote button doesn't appear until they pass; the harness prompt is guidance, not the control.Promote flow (v1, per the Fable adjudication): every promote requires Byron's tap — including "UI-only." Rationale: in this codebase "UI-only" is fictional — client auth, the role modal, and SW registration all live inside index.html, so no PM-promotable path exists that provably can't touch security behavior; and the tap is the only human checkpoint in the injection chain that can actually read code. It's ~30 seconds on Telegram a few times a week — and the minutes where Byron explains a hesitation are the highest-value mentorship in the whole design. Asymmetry kept: PM-alone one-tap Rollback to the auto-snapshotted prior deploy is always allowed (reverting to known-good never waits on anyone). Graduation criteria, published up front so it isn't paternalism: after ~10 clean promotes and once true static assets (copy, handbook, images) are split out of the index.html monolith into files with no executable surface, the PM earns autonomous promotes for that narrow real path.
Today the flag surface is literally one boolean (showCostbar). Extend meta/config.json:
flags: { "new-landing-cta": { on: true, pct: 50, salt: "a1b2", goal: "register" } }
GET /api/user?flags=1 (already unguarded, already client-cached) returns evaluated flags: deterministic bucket = sha256(identity + salt) % 100 < pct. Same user, same variant, forever — no DB, no library.register, plan, exdone, proof, …) in rec.days / event logs. A nightly rollup writes per-variant counts into the flag record; the PM console Flags tab shows exposures, goal conversions per arm, and an honest "too few users to call it" label below n≈100/arm — at ~tens of users, most tests read directional, not significant, and the UI must say so rather than fake certainty. The self-hosted Plausible script gains custom events as a cross-check.Out-of-app notification is today only: welcome email, invite email, Telegram-to-Byron. Proposed v1 — all reusing sendGmail + the existing weekly cron: (a) weekly board-review email digest ("your review is ready"), (b) drift nudge when quietDays ≥ 5 (the in-app cue, escalated to email, opt-out honored), (c) "your feedback shipped" email. Web push (service worker has no push handler) = phase 2. This is deliberately scoped as the PM's first end-to-end run: they spec it with the copilot, the GLM worker builds it, they A/B the nudge copy with §7, and promote it — the whole loop exercised on a real, safe feature.
A short human-readable doc, CHARTER.md, mirrored to meta/charter.json, editable only by owner:
pmlog/ — an immutable audit trail visible in the Controller.roles call removes the email from the allowlist; their 180-day token dies at the next server check.The Fable pass called the sharpest risk: without accountability, the role degrades into "a human approval button between three AIs" filling use-it-or-lose-it quotas. Countermeasures, all cheap:
pmlog: what shipped, what was declined, why each call was right or wrong. This ritual — not the tooling — is where the mentee actually grows, and it costs nothing to build.| Line | $ / month | Enforcement |
|---|---|---|
| GLM Coding Plan Lite (worker, flat) | $10 | fixed subscription — cannot overrun |
| PM copilot, Opus 4.8 | ≤ $15 hard cap | server-side rec.cap → 429, then flash downgrade |
| Charter lint + flag rollups (flash-lite) | < $1 | per-mode caps |
| Broadcasts, Meet, flags, notifications | $0 | Gmail/Calendar/Blob/Plausible — all existing |
| OpenRouter free tier (overflow worker) | $0 | 200 req/day platform limit |
| Optional: monthly product review on Fable 5 | ~$1 | 1 call/month, pinned |
| Headroom vs. $50 ceiling | ~$13–23 | — |
The PM's spend is structurally capped: one flat sub + one server-enforced cap. There is no action in their permission set that can create new spend categories. (The app's own user-facing AI budget — dailyBudget: 10 in config — is a separate, pre-existing line and stays admin-only.)
pm in roles.json, PM console view (backlog/users/invites scoped), pmlog audit. Mentee can start triaging on day one.pmplan mode, context injection, $15 cap, charter + lint.Open items needing Byron: (1) go/no-go + which mentee; (2) Z.ai Lite signup ($10/mo) at P4; (3) approve CHARTER.md text; (4) pick the PM's north-star metric (proposal: weekly active mentees); (5) dedicated sender mailbox/alias for broadcasts; (6) confirm the PM's Google account has passkey/2FA.
Run 2026-08-23 (claude-fable-5, lenses: blast radius / incentive design / security / cost realism, plus a definitive call on promote autonomy). What it found and what changed:
index.html monolith, and the tap is the only code-literate human checkpoint in the injection chain. Adopted wholesale (§6), with PM-alone rollback kept and published graduation criteria so it reads as apprenticeship, not paternalism.Full critique text: https://mentor-pm.arnao.ai/critique.html (source on disk: [file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/FABLE-CRIT-pm-role.md](file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/FABLE-CRIT-pm-role.md))
| What | Link |
|---|---|
| Live app | https://mentor.arnao.ai |
| Fable critique (full text) | https://mentor-pm.arnao.ai/critique.html |
| This proposal (source) | [file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/PROPOSAL-pm-role.md](file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/PROPOSAL-pm-role.md) |
| Canonical architecture state | [file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/CANONICAL-STATE.md](file:///Users/byronarnao/openclaw-gia/config/workspace/projects/mentor-app/CANONICAL-STATE.md) |
| GLM Coding Plan (worker model) | https://docs.z.ai/devpack/overview |
| GLM plan pricing review | https://codingplan.run/plans/glm-coding-plan |
| OpenRouter free models (incl. glm-5.2:free) | https://openrouter.ai/collections/free-models |
| CAN-SPAM compliance (broadcast rules) | https://www.ftc.gov/business-guidance/resources/can-spam-act-compliance-guide-business |