Idlen

Idlen shows a sponsored card in VS Code, Cursor, and other forks while an AI assistant is working. The card sits beside the editor. You can skip it after 3 seconds. It closes after 15 seconds.
What it does
- Shows that card when a request starts in Cursor chat, Copilot Chat, or Claude Code, and when a terminal agent starts a command.
- Refreshes a sidebar ad on a timer. The default gap is 30 minutes.
- Reads dependency names from package manifests so an ad can match the stack.
- Shows a balance in the status bar and the sidebar after you sign in.
Privacy
The extension watches for create and change events on AI session files. It uses those events to tell that an assistant is working. It does not open the files.
Paths come from AiWaitDetector.ts:
~/.claude/projects/**/*.jsonl
~/.cursor/projects/**/agent-transcripts/**
- The editor
globalStorage directory (the parent of this extension's own global storage folder):
github.copilot-chat/**/*
GitHub.copilot-chat/**/*
anthropic.claude-code/**/*
- The workspace storage directory for the open folder, when the editor provides one (the parent of this extension's workspace storage folder):
GitHub.copilot-chat/**/*
anthropic.claude-code/**/*
chatSessions/**/*
chatEditingSessions/**/*
globalStorage and workspaceStorage are the editor's own folders (VS Code, Cursor, or another fork). A change is ignored unless the path looks like a session: a .jsonl file, a path under agent-transcripts, a path under chatSessions or chatEditingSessions, or a .json file whose path contains session, conversation, or transcript. Paths that end in .log, or that sit in a logs folder, are ignored.
It also watches:
- The terminal command line, when the editor exposes shell integration. That string is the command you ran (
claude, codex, aider, gemini, copilot, and similar). It is not the terminal output. The extension does not call TerminalShellExecution.read().
- The terminal's name, when shell integration is missing.
- Command ids, when the editor reports that a command ran. A submit or send id counts as a request start. The prompt text is not included.
- The scheme and URI of a document that opens or changes. For a normal file it counts how many characters were inserted. Up to 180 characters of that insertion are checked on your machine against a short pattern that looks like code, so a large agent edit can be told apart from typing. That sample is not stored and is not sent.
It reads these manifest files in the workspace and keeps the package names only: package.json, requirements.txt, pyproject.toml, Cargo.toml, go.mod, pubspec.yaml, Gemfile, pom.xml, build.gradle, build.gradle.kts, composer.json, Package.swift, and *.csproj. It does not read source files.
What is sent
Asking for an ad sends the dependency names (or vscode, developer, and coding when no manifest was found), the editor name, the trigger, the format it would prefer, the last format shown, your user id if you are signed in, and the ids of ads already shown this session.
An impression sends:
- ad id
- placement (
wait_slot, notification, inline, sidebar, or the surface that was shown)
- trigger
- editor (Cursor, VS Code, Windsurf, or the host name)
- session id
- user id, if you are signed in
- dependency names
- a view token and a paid amount, when the ad includes them
A click sends:
- impression id
- placement
- trigger
- editor
- hour of day
- session length in minutes
The click does not send your user id again. It is tied to the impression.
A house ad, which has no advertiser, sends your user id if you are signed in, the session id, the editor, the placement, and the trigger. It does not send an ad id.
If you are signed in, the extension also syncs the dependency names and a coarse category, at most once a day.
Opening an ad adds idlen_cid and idlen_ad to the link so the advertiser site can attribute the click. The prompt, your code, the session files, and the terminal output are not added.
Sign-in (email and password, Google, or GitHub) goes to the Idlen account service. The session is stored in the editor's secret storage.
Balance
A signed-in view can add to the balance in the status bar and the sidebar. The amount comes from the server. Preview ads do not add to it. Withdrawals are not open yet. The status bar says the same thing.
Settings
Defaults apply only when you have not set the value yourself.
llmad.enabled: turn ads on or off (default on)
llmad.adFrequency: minutes between interval refreshes, 10 to 120 (default 30)
llmad.adFormats: sidebar, toast, inline, popup (default sidebar and toast)
llmad.triggers: which events fetch an ad. Default is ai_prompt, ai_terminal, and interval. The other events (startup, file save and open, git, builds, tests, idle, and the rest) stay available and are off unless you turn them on.
llmad.showEarningsNotifications: refresh the status bar when the session balance moves
llmad.toastCooldownMinutes: minimum minutes between toasts
llmad.popupCooldownMinutes: minimum minutes between popup ads
The wait-slot card for ai_prompt and ai_terminal does not depend on llmad.adFormats.
Commands
Idlen: Show Panel
Idlen: Login, Idlen: Login with Google, Idlen: Login with GitHub
Idlen: Logout
Idlen: Show Earnings
Idlen: Refresh Ad
Idlen: Show Wait-Slot Ad (Ctrl+Alt+Shift+A, Cmd+Alt+Shift+A on macOS)
Idlen: Open Settings
Idlen: Check AI Tools
Idlen: Open Sponsored Link and Idlen: Open Inline Ad are used by the card and by CodeLens. They are hidden from the Command Palette.
Links
Maintainers
CI on a pull request that touches apps/extension installs dependencies, runs the tests, type-checks, and uploads a VSIX artifact. It does not publish.
Marketplace (Personal Access Token with Marketplace publish):
cd apps/extension
npm test
npm run typecheck
npm run package
npx @vscode/vsce publish --no-dependencies
Open VSX, with OVSX_PAT:
cd apps/extension
npx ovsx publish idlen-*.vsix -p "$OVSX_PAT"
The packaged file is named llmad-<version>.vsix. Bump version in package.json and add a CHANGELOG.md entry before each publish. Do not commit the VSIX.
Support
Questions: support@idlen.io
License
MIT