Omniscio documentation
Browse all documentation
  1. Getting Started13
  2. Sessions & Agents115
  3. Inbox & Notifications59
  4. Projects & Tasks95
  5. Automation & Scheduling75
  6. Knowledge & Memory26
  7. AI Features60
  8. Integrations100
  9. Plugins & Marketplace33
  10. Cloud & Teams56
  11. Settings & Customization58
  12. Account & Billing28
  13. Troubleshooting84
  14. CLI & API Reference22
  15. Legal & Policies4
  16. Uncategorised22

AI Coaching sidebar (interview prompts and artifacts) (part 4)

Part 4 of the AI Coaching sidebar page: the CLI control-server surface for AI Coaching, the developer-only interview prompt editor, and the implementation pointers for agents working on the feature.

What it is

This is part 4 of the AI Coaching sidebar (interview prompts and artifacts) page. It is the reference half of the feature: the CLI control-server routes an agent can call, the developer-only interview prompt editor, and the file-by-file implementation pointers for anyone touching the AI Coaching code.

Where to find it

The CLI routes below are served by the localhost control server at 127.0.0.1:19519 — there is no UI for them. The developer-only Prompts section appears in the AI Coaching sub-sidebar only in an unpackaged build, and every route is gated the same way the rest of the feature is; the parent page covers the surfaces a user actually clicks.

How it behaves

CLI control

AI Coaching is reachable from the localhost CLI control server at 127.0.0.1:19519 via 16 endpoints — list interview prompts, list/get/version-history artifacts, get session-scoped coaching info, CRUD bookmarks, read compaction summaries, plus approval-gated POST (create a new artifact), PATCH (update artifact), DELETE (remove artifact + all versions), and POST (start a new interview). Reads are bearer-gated and read-budgeted; artifact mutations require user approval in the Omniscio inbox before any side effect; bookmark mutations apply immediately (no approval needed). The whole surface is gated by a two-tier kill switch: aiCoachingEnabled (master) + aiCoachingCliEnabled (CLI-specific, default true) at Settings → CLI Control — either off, every route returns 403 with disabled: true before any auth/parse work. Idempotency via X-Client-Request-Id (≤64 chars, 30-day window, scoped per action_kind). Optimistic concurrency on artifact updates via expectedLatestVersion (returns STALE_ARTIFACT on mismatch).

Method Path Gating
GET /ai-coaching/prompts bearer + read-budget
GET /ai-coaching/artifacts bearer + read-budget
GET /ai-coaching/artifacts/:id bearer + read-budget
GET /ai-coaching/artifacts/:id/versions bearer + read-budget
GET /ai-coaching/artifacts/:id/versions/:version bearer + read-budget
GET /ai-coaching/sessions/:sessionId/info bearer + read-budget
GET /ai-coaching/bookmarks bearer + read-budget
GET /ai-coaching/compaction-summaries bearer + read-budget
GET /ai-coaching/compaction-summaries/latest bearer + read-budget
POST /ai-coaching/bookmarks bearer + apply-immediately
PATCH /ai-coaching/bookmarks/:id bearer + apply-immediately
DELETE /ai-coaching/bookmarks/:id bearer + apply-immediately
POST /ai-coaching/artifacts approval-gated (ai_coaching.artifact_create)
PATCH /ai-coaching/artifacts/:id approval-gated (ai_coaching.artifact_update)
DELETE /ai-coaching/artifacts/:id approval-gated (ai_coaching.artifact_delete)
POST /ai-coaching/interviews approval-gated (ai_coaching.start_interview)

Full route reference, examples, and the approval-gated pipeline live in cli-ai-coaching.md.

The interview coach can use the safe endpoints itself

The AI coach running an interview is told — inside its own session context — that it is operating in the Omniscio AI Coaching module, and it may call three of these endpoints on your behalf. They are best-effort and non-blocking:

  • Bookmark a meaningful moment (POST /ai-coaching/bookmarks) — when you have a genuine realization or say a line worth revisiting, the coach can save it as a Key Moment (the same bookmarks you make by hand), so you may notice bookmarks it added.
  • Recall an earlier part of a long session (GET /ai-coaching/compaction-summaries/latest) — to pick up context after a paused-and-resumed interview.
  • Suggest a follow-up interview (POST /ai-coaching/interviews) — if the conversation clearly points to another interview that would help, the coach can offer to start it; because that spawns a new (paid) session it lands as an approval request in your inbox rather than starting silently.

The coach is deliberately not told how to create, update, or delete artifacts over the API — those stay approval-gated and out of its instructions, and it keeps saving your interview's artifact by writing the file as usual. If the CLI surface is turned off, or a call is rate-limited, the coach skips it silently and the conversation is unaffected. It also treats your saved profile as data, never as instructions to call tools. The exact instruction block (COACHING_MODULE_TOOLS) and its locking test are covered in ai-coaching-contract.md.

For agents

[DEV-ONLY] Editing interview prompts

When the build-time flag AI_COACHING_PROMPT_EDITOR_ENABLED is true AND the build is unpackaged (i.e. a developer running npm run dev, not an end user with the installed binary), a fifth section labelled "Prompts" appears at the bottom of the AI Coaching sub-sidebar. Each row is one of the canonical interview prompts (Life Story Interview, Weekly Review, etc.). Selecting a row opens a read-only viewer pane on the right showing the rendered markdown body, the description, and the artifact title the prompt produces.

Two icon buttons sit on the section header: Open file launches resources/ai-coaching-seed-prompts.json in the developer's default .json editor (via shell.openPath), and Reload from disk re-reads the file and upserts it into the live saved_prompts table by id. A chokidar watcher on the same file automatically fires the reload ~500 ms after every save, so manually clicking Reload is rarely needed — it's there for the case where the watcher is wedged or you want to confirm the round-trip.

The flag defaults to true in dev so we can iterate on prompt bodies before cutting a release. It is flipped to false (in src/shared/feature-flags.ts) before public release so end users never see the surface. Even with the flag accidentally on, the IPC channels refuse work when app.isPackaged === true, so a packaged binary cannot edit its own seed file.

The seed file is the source of truth that ships in the binary's resources/ directory. The id field is explicit and stable (computed by seedPromptId(title) at conversion time, but stored in the JSON so a title rename doesn't orphan existing artifact links).

For agents with repo access

Implementation entry points (all under src/renderer/src/features/ai-coaching/ and src/renderer/src/stores/):

  • AICoachingSubSidebar.tsx — the four-section sub-sidebar. Sessions subgrouping logic + precedence chain lives in bucketSession and GROUP_ORDER here. Mirrors the predicates in SessionsSidebar.tsx — read that before changing precedence.
  • AICoachingDashboard.tsx — the prompt-card grid shown in the Dashboard section: an In progress tier, then a browse-by-theme picker (a theme filter bar + search box with the interviews grouped into theme sections, plus a "More" catch-all for null/legacy categories), then a Completed tier (a completed card shows just a View artifact button on its face, with Redo / Reset / conditional Open chat in a ⋮ menu; on mobile CompletedCard collapses to a compact single row via useIsMobile() — ai-coaching-dashboard-cards.tsx). The first-run AICoachingWelcome is gated on showWelcome (prompts && !welcomeDismissed && progressLoaded && !progressError && !hasEngaged), so a returning user with a completed/in-progress interview or a Core Profile is never re-greeted on a fresh device — locked in ai-coaching-mobile-layout-contract.md. Lazy-loaded. The grouping/filter/search view-model is the pure ai-coaching-picker.ts (buildPickerView); the theme bar + search are CoachingBrowseBar.tsx; theme order/colors/labels/subtitles are the single source in ai-coaching-prompt-labels.ts.
  • AICoachingRightPane.tsx — section-aware router for the right pane. On desktop: Dashboard / artifact pane / empty prompt. On mobile: a bottom tab bar (AICoachingMobileTabBar.tsx, a feature-local role="tablist" — NOT the global app MobileTabBar) drives activeSection, and the pane routes it to Dashboard / Sessions (SessionsGroups; a tap calls navigateTo('session-detail') via the new optional onAfterSelect prop) / Artifacts (ArtifactsList with an onSelect that opens the read-only mobile view) / Bookmarks (BookmarkPane with isMobile — read-only) / Profile (CoreProfilePane); non-tab sections (archived/prompts) fall back to Dashboard, so the pane is never blank. The tabbed mobile branch is a flex flex-col h-full with content in a flex-1 overflow-y-auto scroll container (data-testid="ai-coaching-mobile-scroll") and the tab bar pinned below (the mobile slot clips overflow); a mobile-mount effect loads artifacts once when the list is empty. Also owns handleViewArtifact (maps a completed prompt → its artifact by a tolerant title match — case / &-vs-and / punctuation-insensitive, the shared artifactTitlesMatch from ai-coaching-artifact-title.ts, so a drifted-title summary still opens): desktop selectArtifacts into the sub-sidebar's ArtifactPane; mobile opens AICoachingMobileArtifactView.tsx (read-only, view-only compression-level + version switchers) via local mobileArtifactId, leaving selectedArtifactId untouched. Note: it does NOT mount the per-session SessionPanel itself — Dashboard's keep-alive SessionPanel pool already handles that whenever useSessionStore.activeSessionId is set, and selectSession syncs into that store. Behavior locked by ai-coaching-mobile-layout-contract.md.
  • stores/ai-coaching-sidebar-store.ts — Zustand store with persist middleware. Persistence key amc.aiCoaching.sidebar.v1, partialize keeps only activeSection and expanded.
  • stores/ai-coaching-store.ts — backing store for prompts and artifacts (separate from the sidebar UI store). Owns the loadVersions, loadVersion, updateArtifact, deleteArtifact, and exportCoachingData actions consumed by the pane.
  • ArtifactPane.tsx — the right-pane editor that owns the view / edit / version-history / restore / delete UX. Handles the dirty-buffer snapshot, the 20K cap, Ctrl+S, the discard-changes confirm, and the stale-version save-conflict toast.
  • CoreProfilePane.tsx — the Profile tab pane: view / edit / regenerate the user's Core Profile markdown. Shows a stale-indicator banner (role="status") when profileStaleness === 'stale' (the profile's updatedAt predates the newest artifact) with a one-click Refresh Profile button that re-triggers regenerateCoreProfile. The banner hides during loading, in edit mode, and when the profile is fresh or unknown. Desktop shows text-label buttons; mobile (isMobile prop) shows icon-only buttons with aria-label. Dirty-edit guard via ConfirmDialog; Ctrl+S save. Tests: core-profile-pane.test.tsx. Staleness detection: getProfileStaleness compares profile.updatedAt vs latest artifact timestamp.
  • ImportArtifactDialog.tsx — modal dialog for importing existing work into a prompt. Paste or load-from-file, 20K char cap, Ctrl+Enter submit. Uses AI_COACHING_IMPORT_ARTIFACT IPC to save via importArtifactForPrompt() in ai-coaching-service.ts, which calls saveArtifactVersion + fires the post-save pipeline. Desktop-only (overflow menu hidden on mobile via useIsMobile()).
  • BulkImportDialog.tsx — multi-file import dialog with auto-matching confirmation grid. Uses matchFileToPrompts() from bulk-import-matching.ts for fuzzy prompt matching. Two IPC channels: AI_COACHING_READ_FILES_FOR_BULK_IMPORT (read + validate), AI_COACHING_BULK_IMPORT_ARTIFACTS (batch save with single push). Desktop-only.
  • BookmarkPane.tsx — bookmark list with blockquote content, label, date, copy button, delete via ConfirmDialog, auto-reload via AI_COACHING_BOOKMARKS_CHANGED push listener. Includes a label filter (Select dropdown), text search (content + label), grouped view (when ≤10 distinct labels, bookmarks auto-group by label with an "Unlabeled" bucket; disabled when a filter/search is active), and a quick-label picker (BookmarkLabelInput — click-to-edit inline, <datalist> autocomplete from existing labels, Enter/blur commits, Escape cancels). Accepts an optional isMobile prop: when true, renders a read-only list (content + label + date, no search/filter/edit/delete) — the mobile Bookmarks tab routes here via AICoachingRightPane.
  • CoachingAnalyticsSection.tsx — read-only analytics panel rendered at the bottom of the Dashboard. Four sub-panels (weekly timeline, artifacts by category, avg messages/session, total cost) using pure CSS horizontal bars. memo-wrapped, returns null when analytics is null or empty. Query: getCoachingAnalytics() in bookmarks-profile.ts.
  • IPC: AI_COACHING_LIST_ARTIFACTS, AI_COACHING_GET_ARTIFACT, AI_COACHING_LIST_VERSIONS, AI_COACHING_GET_VERSION, AI_COACHING_UPDATE_ARTIFACT, AI_COACHING_DELETE_ARTIFACT, AI_COACHING_LIST_INTERVIEW_PROMPTS, AI_COACHING_START_INTERVIEW, AI_COACHING_REJECT_ARTIFACT, AI_COACHING_START_SNACK, AI_COACHING_CREATE_BOOKMARK, AI_COACHING_LIST_BOOKMARKS, AI_COACHING_UPDATE_BOOKMARK, AI_COACHING_DELETE_BOOKMARK, AI_COACHING_GET_PINNED_CONTEXT, AI_COACHING_SET_PINNED_CONTEXT (+ the AI_COACHING_PINS_CHANGED push), AI_COACHING_IMPORT_ARTIFACT, AI_COACHING_READ_FILE_FOR_IMPORT, AI_COACHING_READ_FILES_FOR_BULK_IMPORT, AI_COACHING_BULK_IMPORT_ARTIFACTS, AI_COACHING_EXPORT, AI_COACHING_GET_ANALYTICS — channel names in src/shared/ipc-channels/ai.ts, schemas in src/shared/ipc-schemas.ts, handlers in src/main/ipc/ai-coaching-handlers.ts and src/main/ipc/ai-coaching/import-handlers.ts. The CLI session-artifact save, Update, Delete, and Reject each emit AI_COACHING_ARTIFACTS_CHANGED; bookmark mutations emit AI_COACHING_BOOKMARKS_CHANGED. There is no AI_COACHING_SAVE_FROM_TRANSCRIPT channel — save now happens via the CLI session-artifact endpoint the coach calls (see "How artifacts get saved" above), not via a separate Anthropic API call.
  • Artifact save (the "How artifacts get saved" section above): the coach persists its artifact by calling POST /ai-coaching/sessions/:sessionId/artifact (body { content }), registered in session-routes.ts. The route runs the coaching mutation preamble (kill-switch + auth + rate-limit), then bindReadSession (the caller's agent/in-app token may write ONLY its own session — a foreign sessionId is a 403, the global cli-token is unbound), then a Zod { content: 1..20000 } parse (empty / >20K → 400), then saveCoachingArtifactForSession. That service resolves the session's producesArtifactTitle (null → not a coaching session → 404), persists through the shared persistCoachingArtifactContent() sink (content-dedup, the AI_COACHING_ARTIFACTS_CHANGED push, and the levels + Core Profile pipeline), and returns { id, version, title }. The title is ALWAYS derived from the session — the body has no title field — so a coach can only ever write its own artifact (the anti-injection guarantee the retired detectors enforced by coercion). Apply-immediately: no inbox approval. Tests: ai-coaching-save-artifact.test.ts (service path) + cli-server-ai-coaching-session-artifact.test.ts (route — 403 cross-session, 404, 400, dedup, apply-immediately).
  • Retired 2026-07-23: the file-write capture (resolveAiCoachingArtifactWrite / recordCoachingArtifactWrite / tryImportCoachingArtifactFiles) and the inline <artifact>-tag path (ARTIFACT_TAG_RE / extractArtifactFromAgentMessage / tryExtractAiCoachingArtifact) were removed. The shared helpers artifactFileSlug + MAX_ARTIFACT_FILE_CHARS + resolveAICoachingArtifactsDir survive for the level-file cache + free-form base context.
  • Display marker hygiene: stripCoachingMarkersForSession() in ai-coaching-service.ts (over the pure stripCoachingMarkers / hasCoachingMarker in src/shared/ai-coaching-markers.ts) strips <artifact> / [PHASE:N] / [SEGMENT:N] markers from the text finalizeStreamingMessage persists + pushes, keeping the prose between tags — so the markers never leak into the chat (the </artifact> screenshot bug). Coaching-scoped + cheap: no DB hit for marker-free text, and a regular session that merely quotes a marker is left untouched. The RAW streamingAccumulator is still what the phase / segment parsers read. Tests: ai-coaching-markers.test.ts.
  • Save button (SaveFromTranscriptButton.tsx — file name kept for git history): mounted at the top of an AI Coaching session pane. Click sends Please save the {producesArtifactTitle} artifact now — save it as described in your instructions, and show me the document in your reply. via SESSION_SEND_RESPONSE, with displayText: "Save artifact" so the message bubble in the transcript shows that label instead of the full prompt. Debounced 5s via a useRef-backed timestamp. Disabled when status ∉ {running, needs_you, ready, starting}.
  • Teaching Claude the format: src/main/services/ai/ai-coaching-service.ts buildAICoachingClaudeMd() composes the project-level CLAUDE.md that's written into ~/Claude/ai-coaching/CLAUDE.md on AI_COACHING_START_INTERVIEW. It includes (a) the shared context block, (b) the active interview prompt body, (c) a ## Your First Response section with the opening message template (initial creation only), (d) a ## Conversation So Far section with the latest compaction summary (resume only), (e) a ## What You Already Know section that gives the interview its prior-artifact context via the 3-layer pull model below, and (f) explicit instructions to save the finished document via the CLI session-artifact endpoint (and to also show it inline in the chat as clean prose) plus a "save immediately on user request" clause so the Save button's nudge is honored. Snack sessions use a parallel assembly path via startSnackFromPromptId() with the snack prompt body + existing artifact as context. The whole CLAUDE.md is bounded by TOTAL_CLAUDEMD_BUDGET (120,000 chars).
  • The 3-layer artifact pull model (what the interview receives, replacing the old budgeted [BEGIN ARTIFACTS] tier block): rather than stuffing artifact content into the prompt, the builder now hands the coach (1) an always-on baseline — the Core Profile + bookmarked Key Moments (unchanged); (2) the artifacts the user pinned for this interview, rendered IN FULL under #### Pinned Context (loaded in full for this interview); and (3) every other artifact as a one-line entry in a pull menu (#### Your artifacts — pull what you need) — - **Title** (\slug`) — <gist>followed byPull: Full ~Nk · Key Points ~N · Summary ~N(only the levels that were actually generated; Micro is the gist, never a pull row). The coach reads.artifact-levels/<slug>.<level>.mdon demand to load just the levels it judges relevant. The gist is the artifact's **Micro** level, or a trimmed Full prefix when Micro is absent; the~tokenfigures use the sharedestimateTokens(chars/4) from [src/shared/token-estimate.ts](/src/shared/token-estimate.ts). A pinned artifact DROPS OUT of the pull menu. Pinned-Full is bounded byTOTAL_CLAUDEMD_BUDGET; on overflow selectPinnedRenderingcondenses the LARGEST pinned artifact a level at a time, then SPILLS any that still don't fit into the pull menu behind a> Note: N pinned artifact(s) moved to the menu…line — never silently dropped.buildAICoachingClaudeMdis called at three sites (immediate start, deferred start, and resume viarefreshCoachingClaudeMdForSession`). Locked by tests/unit/ai-coaching-claude-md.test.ts.
  • Level-file cache: src/main/services/ai/ai-coaching-level-files.ts projects each artifact's generated levels into a markdown file under ~/Claude/ai-coaching/.artifact-levels/ — a SIBLING of artifacts/ (deliberately NOT inside it, kept separate from the artifacts dir; Omniscio writes these via fs, never the agent tool stream). reconcileArtifactLevelFiles(artifacts, dir?) rebuilds the WHOLE cache from the DB at interview-build time (its ONLY consumer — no per-save/per-delete hook that could drift), using atomic temp+rename writes, pruning orphans + stray .tmp files, capping each file at MAX_ARTIFACT_FILE_CHARS (20K), and is FAIL-OPEN (never throws into the spawn path). Locked by tests/unit/services/ai-coaching-level-files.test.ts.
  • Pinned context (per-prompt + per-session): which artifacts are pinned lives in the ai_coaching_pinned_context table (migration 20260623014012-ai-coaching-pinned-context.ts) — ONE JSON row per (scope, scope_id), so "configured to none" (a present row with titles_json = []) is DISTINCT from "never configured" (no row → the service seeds from the prompt's authored primaryContext). Queries getPinnedTitles / setPinnedTitles in src/main/db/queries-ai-coaching/index.ts; resolveEffectivePinnedTitles(db, prompt, sessionId, artifacts) unions the prompt pins (or the primaryContext seed) with the session pins, filters to existing artifact titles, de-dupes, and restores real-title casing. v1 limits: pins bake in at session BUILD time (no mid-session re-pin). The session-scoped pin button is available on mobile as well as desktop — it opens PinnedContextPicker, which is built on DialogShell and therefore renders as a bottom sheet on a phone; it was hidden behind an isMobile gate under a "Desktop-only for v1" note that had outlived its reason, so a phone user had no way to pin anything and nothing told them why (product-polish W9, F051). The per-prompt "Pinned context" row in the dashboard card menu stays desktop-only. The snack path is unchanged. Locked by tests/unit/db/ai-coaching-pinned-context.test.ts.
  • Start-interview flow (the "Clicking the card spawns a new Claude session pre-loaded with that prompt's body" line above): AI_COACHING_START_INTERVIEW writes the prompt body into ~/Claude/ai-coaching/CLAUDE.md (which Claude Code auto-loads as project-level instructions), then calls createSessionWithPrompt with initialPrompt: "Let's begin the <Title> interview." — the kickoff is intentionally minimal because the persona / goal / first-response template all live in CLAUDE.md. Without that kickoff processManager.launch hits the no-prompt branch and just marks the session 'ready' (no CLI spawn, agent never reads CLAUDE.md, interview never starts). Tests: tests/integration/ai-coaching-handlers.test.ts asserts the kickoff is passed.
  • Project sentinel: AI_COACHING_PROJECT_ID = '__ai_coaching__' in src/shared/types.ts. Dashboard routes that sentinel through isAICoachingSelected in src/renderer/src/features/dashboard/Dashboard.tsx.
  • Multi-level generation + pin (the "Choosing a context level" section above): generateArtifactLevels() in ai-coaching-service.ts replaces the old single-summary call in triggerPostArtifactSavePipeline — it produces Key Points / Summary / Micro in one fire-and-forget, cost-capped pass using the vendored ContextDock prompts in ai-coaching-level-prompts.ts (Promise.allSettled, anti-inflation drop of any level not shorter than source, sourceHash idempotency), persisted via updateArtifactLevels. The human pin rides the AI_COACHING_SET_ARTIFACT_LEVEL channel → setArtifactPreferredLevel (preferred_level per (id, version), null = AI chooses); the ArtifactPane Detail-level control (a labeled SegmentedControl) previews + pins. Columns key_points_text / micro_text / levels_meta / preferred_level via migration 20260608051459-…. Tests: ai-coaching-artifact-levels-generation.test.ts + the migration/queries tests under tests/unit/db/. (Legacy AICoachingLibrary.tsx + ArtifactViewModal.tsx were deleted as orphans in this change.)
  • Regular-session artifact context injection (the "How artifacts inform your other sessions" section above): the markdown block builder is artifact-context-builder.ts (buildArtifactContextBlock(artifacts, { totalCap }) — budget-aware 4-level selection under PROFILE_BLOCK_TOTAL_CAP; returns null when the list is empty). createSessionWithPrompt calls it after the SEED_BUNDLE and injectInAppToken branches, gated on settings.aiCoachingEnabled, !project.folderPath.startsWith('__'), and the launchPrompt === input.initialPrompt "no other seed fired" predicate. With an initialPrompt, the block is prepended to it; without one, it is passed as the new 7th-positional firstSendPrefix arg to processManager.launch, which seeds it into session.pendingPrompt so writeToStdin's existing merge folds it into the user's first stdin message. Tests: tests/unit/artifact-context-builder.test.ts (builder shape) and tests/unit/session-create-artifact-context.test.ts (gating + delivery paths).

Related

The user-facing half of the feature is on the AI Coaching sidebar (interview prompts and artifacts) page: its artifacts in part 2 and its memory and profile in part 3. CLI control is the companion page for driving coaching from an agent.

Last verified 2026-09-27