analyze-code
CommandAnalyze code quality, identify issues, and suggest improvements.
Author a new contextual tip for Nimbalyst's tips system (transcript-inline tip cards with trigger/targeting rules).
> /plugin marketplace add nimbalyst/nimbalyst> /plugin install nimbalyst-wiki@nimbalyst
name: tip description: Author a new contextual tip for Nimbalyst's tips system (transcript-inline tip cards with trigger/targeting rules).
Author a new contextual tip: {{arg1}}
A **contextual tip** is a small, dismissible card Nimbalyst shows in the empty panel of a new AI session to teach users a feature they have not discovered yet. We are adding many of these to help users get the most value from Nimbalyst. This command walks you through writing one correctly.
If `{{arg1}}` is empty, ask the user what feature/behavior the tip should teach and who should see it, then proceed.
All code lives under `packages/electron/src/renderer/tips/`.
Tips render **inline in the empty panel of a new/unused AI session transcript** — not as a floating popup (the floating `TipCard` variant exists but is dormant). The surface is wired in `SessionTranscript.tsx` via `renderEmptyExtra()`, which mounts `InlineTipDisplay` above the slash-command suggestions when `messages.length === 0`.
`TipProvider.tsx` runs an evaluation loop. A tip is **eligible** only when ALL of these hold: 1. Not shown yet this app launch (`tipShownThisSession` — in-memory, one tip per launch, resets on restart). 2. Help/tips master toggle is on (`walkthroughState.enabled`), no walkthrough active, no dialog/overlay visible, no tip already active. 3. An empty-transcript surface is mounted (`emptyTranscriptVisibleCountAtom > 0`). 4. Not previously dismissed or completed (`shouldShowTip` in `TipService.ts`) — unless `version` was bumped. 5. `trigger.screen === '*'` OR matches the current `ContentMode` (e.g. `'agent'`, `'files'`, `'tracker'`). 6. `trigger.condition(context)` returns `true`.
Among eligible tips, the highest `priority` wins; then it waits `trigger.delay` ms and re-checks the condition before showing. The loop only starts ~15s after launch and re-evaluates every 5s, reading live state from refs.
The `condition` receives a `TipTriggerContext`:
interface TipTriggerContext {
currentMode: ContentMode;
workspacePath?: string;
isGitRepo: boolean;
isWorktreesAvailable: boolean;
featureUsage: Record<string, FeatureUsageRecord>;
hasBeenUsed: (feature: string) => boolean; // count > 0
hasReachedCount: (feature: string, threshold: number) => boolean; // count >= threshold
}Most tips follow the pattern "user has done X enough times but never used Y" — e.g. `hasReachedCount(SESSION_CREATED, 10) && !hasBeenUsed(WORKTREE_CREATED)`. The condition must be a **pure, synchronous** predicate (no async, no IPC).
Tips reuse the walkthrough store via IPC (no new tables). IDs MUST start with `tip-`. Bumping `version` re-shows a tip to users who dismissed an older version. PostHog events (`tip_shown`, `tip_dismissed`, `tip_action_clicked`, `tip_navigated`, `tip_all_tips_opened`) are captured automatically — do not add your own.
Decide what user state should surface this tip. If you can express it with an existing key in `FEATURE_USAGE_KEYS` (`packages/electron/src/shared/featureUsage.ts`), use it. Current keys include: `SESSION_CREATED`, `SESSION_COMPLETED`, `APP_LAUNCH`, `AI_PROMPT_SUBMITTED`, `EXCALIDRAW_OPENED`, `MOCKUP_OPENED`, `SPREADSHEET_OPENED`, `DATAMODEL_OPENED`, `TRACKER_USED`, `THEME_CHANGED`, `KEYBOARD_SHORTCUT_USED`, `FILE_CREATED`, `WORKTREE_CREATED`.
If no key fits, you must add a new one (see step 4) AND wire a `recordUsage` call at the feature's call site — otherwise the condition can never flip and the tip will never show. Confirm with the user before introducing a new key.
`packages/electron/src/renderer/tips/definitions/<kebab-name>.tsx`. Match the style of a nearby tip such as `worktree-session.tsx`. Prefer `<MaterialSymbol icon="..." size={16} />` for the icon. Drive actions through atoms/IPC/`dialogRef` like the existing tips do — never reach into DOM.
**Action options.** A tip's `content.action` can either:
import { MaterialSymbol } from '@nimbalyst/runtime';
import { store } from '@nimbalyst/runtime/store';
import { FEATURE_USAGE_KEYS } from '../../../shared/featureUsage';
import type { TipDefinition } from '../types';
const Icon = <MaterialSymbol icon="lightbulb" size={16} />;
export const myFeatureTip: TipDefinition = {
id: 'tip-my-feature', // MUST start with 'tip-'
name: 'My Feature Suggestion', // human-readable, used in analytics
version: 1, // bump later to re-show after dismissal
trigger: {
screen: '*', // or 'agent' | 'files' | 'tracker' | ...
condition: (ctx) =>
ctx.hasReachedCount(FEATURE_USAGE_KEYS.SESSION_CREATED, 5) &&
!ctx.hasBeenUsed(FEATURE_USAGE_KEYS.MY_FEATURE),
delay: 2500, // ms after eligible before showing (default 2000)
priority:Nimbalyst - The open-source visual workspace for Claude Code, Codex, and OpenCode. Run multiple coding agents in parallel, edit their work visually in markdown, mockups, and diagrams, and track tasks. Free, MIT-licensed desktop app for macOS, Windows, Linux, with mobile companion for iOS and Android.
Analyze code quality, identify issues, and suggest improvements.
Audit recent AI coding sessions to find repeated mistakes, speed losses, and missed Nimbalyst tool usage — then propose harness…
Triage pnpm audit findings and produce a prioritized, supply-chain-cautious package-update plan, then apply approved batches
Survey recently triaged GitHub issues, propose the ones safe to fix without a product decision, and fan the selected ones out to…
Gather details and draft an actionable bug report for developers.
Shortcut for "continue working" — pick the work in flight back up exactly where it stopped and keep going until it is done or…