Skip to content

moooon

Motir

Vibe your whole project. Bring an idea — Motir's three AI layers plan it, track it, and ship it, end to end. You're looking at Motir, built in Motir.

  • Vibe Project
  • Open Source
  • AI Agent
  • AI Loop
1
requests
0
upvotes
145
planned
1,361
shipped

Motir · Work items

MOTIR-2355Done

`ai:plan` (1/4) — the conversational planners: the discovery chat and the plan-change session

The first of four cards that wire ai:plan, split by the service that owns each job so no single PR touches eleven services. This one takes the two conversational surfaces — the discovery chat and the plan-change session — five routes in total.

OperationService methodToday
POST /api/ai/chataiChatService.submitDiscoveryTurnnothing
POST /api/ai/plan-change/sessionplanChangeSessionsService.getOrCreateForProjectnothing
POST /api/ai/plan-change/session/turnsplanChangeSessionsService.appendTurnassertCanEdit
POST /api/ai/plan-change/session/submitplanChangeSessionsService.submitassertCanEdit
POST /api/ai/plan-change/session/planner-turnplanChangeSessionsService.recordPlannerTurn, contextualPlanningService.recordPlannerTurnForWorkItemassertCanBrowse

Two of these reach no gate at all: starting a plan-change session and sending a discovery turn are, today, available to any signed-in workspace member with the project open. Both spend the workspace's AI credits.

The planner-turn route is not the same shape as the others. It records what the PLANNER said, so its caller may be a job callback rather than a person. Read the route before gating it: if the actor is the signed-in user relaying a result, ai:plan is right; if it is a service-to-service callback, it belongs on the serviceAuth axis and its inventory row is corrected rather than gated — say which in the PR body, with the line you read.

Acceptance criteria

  • submitDiscoveryTurn, getOrCreateForProject, appendTurn and submit each assert projectAccessService.assertPermission(projectId, ctx, 'ai:plan') before doing anything else, in the service.
  • The planner-turn path is either gated on ai:plan or recorded as service-authenticated with its inventory row corrected — one of the two, decided from the code and stated in the PR body.
  • A unit test proves a project viewer is refused every gated method, and that a workspace member with NO project membership is refused on an open project — the second case is the one ai:plan-at-member is really about, and it does not follow from the first.
  • ai:plan does NOT flip to enforcement: 'enforced' here: three sibling cards still hold ungated ai:plan operations, and the flag may only turn when the last of them lands. The close-out card owns the flip. tests/permissions/catalog.test.ts is therefore unchanged by this PR.
  • The inventory rows for these five operations record the gate that landed.
  • The guard's pinned counts are re-derived by running it on this branch.
  • pnpm test tests/permissions/ tests/services/ is green.

Context refs

  • lib/services/aiChatService.ts, lib/services/planChangeSessionsService.ts, lib/services/contextualPlanningService.ts — the three services this card gates.
  • app/api/ai/plan-change/session/planner-turn/route.ts — the route whose caller must be read before it is gated.
  • docs/decisions/member-facing-permissions.md — the role assignment for ai:plan, including the implicit-workspace-member answer.
  • The role-set seam — the prerequisite.
  • lib/services/projectAccessService.tsassertPermission.