/tip
Author a new contextual tip for Nimbalyst's tips system (transcript-inline tip cards with trigger/targeting rules).
$ npx -y skills add nimbalyst/nimbalyst --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/tip
Context preview
What this command does when you run it.
Author a new contextual tip for Nimbalyst's tips system (transcript-inline tip cards with trigger/targeting rules).
Command definition
tip.mdname: 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.
How the tips system works (read before writing)
All code lives under `packages/electron/src/renderer/tips/`.
Where a tip is displayed
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`.
- The card shows: icon + title + body (basic markdown) + optional primary action button + optional secondary link.
- Footer controls: **Next** (cycles through tips, sorted by priority) and **All tips** (opens `AllTipsDialog` to browse every tip).
- Dismiss = X button; primary action = `markTipCompleted`; both clear the active tip.
- Body markdown (`parseMarkdownBody` in `TipCard.tsx`) supports only: `**bold**`, paragraph breaks (blank line), and bullet lists (`- ` / `* `). No links, headings, or inline code.
How targeting / rules work
`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).
Persistence & analytics
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.
Steps to author the tip
1. Pick the trigger signal
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.
2. Create the definition file
`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:
- run code via `onClick` (navigate, open a dialog, set an atom), or
- seed the composer via `insertPrompt: '/some-command '` — drops that text into the session input so the user can review and submit. Use this to point at a slash command (e.g. a planning-extension command). `insertPrompt` only works in the inline surface of a **claude-code** session; the button is hidden automatically where there's nowhere to insert, so keep the body meaningful without it. See `session-cleanup.tsx`.
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:Read more
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.
How the tips system works (read before writing)
All code lives under `packages/electron/src/renderer/tips/`.
Where a tip is displayed
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`.
- The card shows: icon + title + body (basic markdown) + optional primary action button + optional secondary link.
- Footer controls: **Next** (cycles through tips, sorted by priority) and **All tips** (opens `AllTipsDialog` to browse every tip).
- Dismiss = X button; primary action = `markTipCompleted`; both clear the active tip.
- Body markdown (`parseMarkdownBody` in `TipCard.tsx`) supports only: `**bold**`, paragraph breaks (blank line), and bullet lists (`- ` / `* `). No links, headings, or inline code.
How targeting / rules work
`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).
Persistence & analytics
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.
Steps to author the tip
1. Pick the trigger signal
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.
2. Create the definition file
`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:
- run code via `onClick` (navigate, open a dialog, set an atom), or
- seed the composer via `insertPrompt: '/some-command '` — drops that text into the session input so the user can review and submit. Use this to point at a slash command (e.g. a planning-extension command). `insertPrompt` only works in the inline surface of a **claude-code** session; the button is hidden automatically where there's nowhere to insert, so keep the body meaningful without it. See `session-cleanup.tsx`.
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.
Repo: nimbalyst/nimbalyst
Other commands on nimbalyst.
analyze-sessions
Audit recent AI coding sessions to find repeated mistakes, speed losses, and missed Nimbalyst tool usage — then propose harness improvements
audit-updates
Triage npm audit findings and produce a prioritized, supply-chain-cautious package-update plan, then apply approved batches
autofix-issues
Survey recently triaged GitHub issues, propose the ones safe to fix without a product decision, and fan the selected ones out to independent sessions.

