Skip to content
Productivity
Command

/tip

Author a new contextual tip for Nimbalyst's tips system (transcript-inline tip cards with trigger/targeting rules).

From plugin
nimbalyst
2.1k54 skills3 agents54 commands3 MCP
> /plugin marketplace add nimbalyst/nimbalyst
> /plugin install nimbalyst-wiki@nimbalyst

Command definition

tip.md
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:
Read more
@nimbalyst
Ships withnimbalyst

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.

2.1k16 skills3 agents3 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
2.1k
Star history of nimbalyst/nimbalyst on GitHub, a chart by star-history.com

Other commands on nimbalyst.

analyze-sessions

analyze-sessions

Command

Audit recent AI coding sessions to find repeated mistakes, speed losses, and missed Nimbalyst tool usage — then propose harness…

@nimbalyst@nimbalystInstall Command
audit-updates

audit-updates

Command

Triage pnpm audit findings and produce a prioritized, supply-chain-cautious package-update plan, then apply approved batches

@nimbalyst@nimbalystInstall Command
autofix-issues

autofix-issues

Command

Survey recently triaged GitHub issues, propose the ones safe to fix without a product decision, and fan the selected ones out to…

@nimbalyst@nimbalystInstall Command

More commands from other plugins.

analyze-cohorts

analyze-cohorts

Command

Perform cohort analysis on user data — retention curves, feature adoption, and engagement trends

@phuryn@phurynInstall Command
again

again

Command

PUA Again — 用于再试试、换个方法、别放弃、为什么还不行、同一路径失败多次;要求停止微调同一思路,改用本质不同方案。

pua2mo20k
@tanweai@tanweaiInstall Command