feat: Read My Mind phase 1, per-case intent profiles (capture + API + skill)

Per-case profiles of user intent (docs/readmymind-plan.md): user-stated goals
plus the user's recently submitted prompts, captured from the Claude session
transcript behind the new synced readMyMindEnabled setting (default OFF).

- intent-store.ts: keyed by owner + realpath(workingDir), FIFO/size caps,
  consecutive-dupe collapse, atomic 0600 writes to ~/.codeman/intents.json
- transcript-watcher.ts: new transcript:user_prompt event for typed user turns
  (tool_result-only entries stay silent); capture wiring in server.ts is
  claude-only and gated on the setting per event
- readmymind-routes.ts: GET/PUT/DELETE /api/sessions/:id/intent, ownership
  via findSessionOrFail, strict Zod schema
- agent skill: SKILL.md recipe + endpoints.md rows so agents can read and
  record intent (PUT replaces: read + merge; never delete unprompted)
- groundwork for the phase-2 predictor button; nothing is ever auto-sent

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer
2026-08-09 18:03:13 +02:00
parent 3533c4332b
commit 161f1da2eb
17 changed files with 983 additions and 4 deletions
+17
View File
@@ -700,6 +700,16 @@ export const ApprovalAnswerSchema = z
})
.strict();
/**
* Body of PUT /api/sessions/:id/intent (Read My Mind). The 8192 cap mirrors
* MAX_GOALS_CHARS in intent-store.ts.
*/
export const IntentGoalsSchema = z
.object({
goals: z.string().max(8192),
})
.strict();
// ========== Configuration ==========
/**
@@ -809,6 +819,13 @@ export const SettingsUpdateSchema = z
* already pending immediately.
*/
approvalsInboxEnabled: z.boolean().optional(),
/**
* Read My Mind (docs/readmymind-plan.md): capture the user's submitted
* prompts into per-case intent profiles. SYNCED, default OFF (opt-in:
* captured prompts are sensitive). OFF stops capture immediately; already
* stored profiles stay until DELETE /api/sessions/:id/intent.
*/
readMyMindEnabled: z.boolean().optional(),
tunnelEnabled: z.boolean().optional(),
// Action field (NOT persisted): explicit per-request acknowledgment that the
// operator accepts exposing an UNAUTHENTICATED public tunnel (no CODEMAN_PASSWORD).