
Analysis Api Mark Internal Apis
- 1 installs
- 53.3k repo stars
- Updated August 5, 2026
- jetbrains/kotlin
analysis-api-mark-internal-apis skill documents Drive the per-module internal-API codebase test, then refine the suggested annotations down to `internal` (or up to `@KaImplementationDetail`) based on actual external usag
About
analysis-api-mark-internal-apis skill documents Drive the per-module internal-API codebase test, then refine the suggested annotations down to `internal` (or up to `@KaImplementationDetail`) based on actual external usage. name: analysis-api-mark-internal-apis description: Drive the per-module internal-API codebase test, then refine the suggested annotations down to `internal` (or up to `@KaImplementationDetail`) based on actual external usage
- Drive the per-module internal-API codebase test, then refine the suggested annotations down to `internal` (or up to `@Ka
- Platform-specific setup patterns for analysis-api-mark-internal-apis.
- Evidence-backed steps from upstream SKILL.md.
- When-to-use criteria for analysis-api-mark-internal-apis versus alternatives.
Analysis Api Mark Internal Apis by the numbers
- 1 all-time installs (skills.sh)
- Ranked #644 of 782 Skill Development skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
analysis-api-mark-internal-apis capabilities & compatibility
- Capabilities
- analysis api mark internal apis quick start · analysis api mark internal apis when to use guid · analysis api mark internal apis integration patt
- Use cases
- documentation
- IDEs
- intellij · jetbrains
What analysis-api-mark-internal-apis says it does
disable-model-invocation: true
argument-hint: "[--intellij=<path>]"
npx skills add https://github.com/jetbrains/kotlin --skill analysis-api-mark-internal-apisAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 53.3k |
| Last updated | August 5, 2026 |
| Repository | jetbrains/kotlin ↗ |
How do I use analysis-api-mark-internal-apis correctly?
Drive the per-module internal-API codebase test, then refine the suggested annotations down to `internal` (or up to `@KaImplementationDetail`) based on actual external usage
Who is it for?
Teams implementing analysis-api-mark-internal-apis workflows from the catalog.
Skip if: Skip when requirements clearly match a different specialized stack.
When should I use this skill?
User asks about analysis-api-mark-internal-apis, drive the per-module internal-api codebase test, then refine the suggested annotations dow.
What you get
Working analysis-api-mark-internal-apis setup with validated configuration and next steps.
Files
Mark Internal APIs in Analysis API Implementation Modules
Public declarations in Analysis API implementation modules should not be exposed to users. They should be internal or annotated with a visibility annotation. The codebase test `AbstractAnalysisApiInternalApiTest` already finds unmarked declarations and chooses a default annotation per module/package. This skill runs that test in auto-apply mode, then refines each freshly marked declaration: downgrade to internal when it has no callers outside its module, upgrade @LLFirInternals to @KaImplementationDetail when its callers reach outside analysis/low-level-api-fir/, and keep the rest. Finally, fix any "internal exposed through public API" build errors by re-promoting internal declarations to @KaImplementationDetail.
Reference: Read Guard API Endpoints with Annotations for the full annotation guide and placement rules.
Inputs
Module selection (required)
Use AskUserQuestion to present a selection of modules. The user must pick one. Only modules that have a per-module codebase test are listed here:
| Choice | Module path (project-relative) | Gradle codebase test task |
|---|---|---|
analysis-api-fir | analysis/analysis-api-fir | :analysis:analysis-api-fir:testCodebase |
analysis-api-impl-base | analysis/analysis-api-impl-base | :analysis:analysis-api-impl-base:testCodebase |
low-level-api-fir | analysis/low-level-api-fir | :analysis:low-level-api-fir:testCodebase |
Throughout this skill, <module> and <gradle-task> refer to the user's selection.
Optional flags
| Input | Flag | Default | Description |
|---|---|---|---|
| IntelliJ repo | --intellij=<path> | ../ultimate (relative to project root) | Path to the IntelliJ repository for additional usage search |
---
Annotations Reference
The codebase test owns the initial choice of marker for each unmarked declaration. The test's per-module logic lives in the suggestedAnnotation overrides:
analysis-api-fir,analysis-api-impl-base→ always@KaImplementationDetail.low-level-api-fir→@KaImplementationDetailfor declarations inorg.jetbrains.kotlin.analysis.low.level.api.fir.api
(and subpackages); @LLFirInternals for everything else.
The set of annotations the test treats as already-marked (so they're never flagged) lives in `AnalysisApiNonPublicMarkers`: @KaImplementationDetail, @KaExperimentalApi, @KaPlatformInterface, @KaNonPublicApi, @KaIdeApi, @LLFirInternals. The test also skips internal/private declarations, annotation class declarations annotated with @RequiresOptIn, and declarations carrying override. None of those reach this skill.
The skill then refines the test's suggestion based on actual external usage. The rules differ slightly per module because of how sub-modules see each other:
In every implementation module, src/ and the test source sets are separate Kotlin modules — an internal declaration in src/ is not visible from tests/ or testFixtures/. That's why "used in own tests" is enough to disqualify a declaration from being internal. Only low-level-api-fir has its own opt-in marker (@LLFirInternals) for "test-accessible LL-FIR-internal" declarations; the other modules don't have a similar marker because their implementations don't go that deep, and @KaImplementationDetail is the catch-all for cross-sub-module visibility there.
| Test's suggestion | Where the declaration is referenced (besides own src/) | Action |
|---|---|---|
@KaImplementationDetail | Nowhere (only own src/) | Downgrade to internal |
@KaImplementationDetail | Anywhere else (own tests, outside the module, IntelliJ) | Keep |
@LLFirInternals | Nowhere (only own src/) | Downgrade to internal |
@LLFirInternals | Only inside analysis/low-level-api-fir/ (own tests/testFixtures, no usages outside) | Keep |
@LLFirInternals | Anywhere outside analysis/low-level-api-fir/ | Upgrade to @KaImplementationDetail |
The skill never adds annotations to declarations the codebase test didn't already touch — Phase 5 just builds and reports any remaining errors for manual review.
---
Phase 1: Run the codebase test in auto-apply mode
Replace any manual scan. The test discovers and annotates one violating file per run.
Step 1: Invoke the test with auto-apply enabled
./gradlew <gradle-task> \
-Pkotlin.analysis.codebaseTest.internalApi.updateSourceCode=true \
-Pkotlin.test.instrumentation.disable.inputs.check=truekotlin.analysis.codebaseTest.internalApi.updateSourceCode=trueflips the abstract test into write-back mode: it writes
the suggested fix to the violating source file, then throws to stop iteration.
kotlin.test.instrumentation.disable.inputs.check=truedisables the test-input security manager so the test JVM is
allowed to write to source files.
Step 2: Interpret the outcome
- Test passes (BUILD SUCCESSFUL): every public declaration in
<module>/src/is already marked correctly. Skip to
Phase 5 to perform a final build check.
- Test fails with `"Auto-applied N marker annotation(s) to <File>.kt. ..."`: exactly one source file under
<module>/src/ was modified on disk. The next phases work on that file.
If the test fails with a different message (compile error, security exception, etc.), stop and report the error to the user — the skill cannot make sense of unrelated failures.
Step 3: Identify the modified file
Use git diff --name-only (filtered to files under <module>/src/):
git diff --name-only -- '<module>/src/'If multiple files are reported, prefer the one the test message named (the message contains the file's basename). Other files in the diff are likely the user's pre-existing edits — don't touch them.
---
Phase 2: Diff, downgrade, upgrade
For the modified file from Phase 1.
Step 1: Extract the newly added annotations
The test only inserts lines of the form <indent>@<MarkerName> directly above a declaration. Use git diff <file> (or mcp__idea__read_file on <file> and on the HEAD version via git show HEAD:<file>) to extract, for each insertion:
- the declaration the annotation precedes (kind, name, FQN);
- the inserted annotation —
@KaImplementationDetailor@LLFirInternals.
Step 2: Classify each declaration's usages
For each newly marked declaration, determine where it is referenced besides its own `src/`:
<module>/tests/,<module>/testFixtures/,<module>/test/count as own tests.- Ignore
<module>/testData/: those are data files, not Kotlin sources, and can mention internal class names without it
being a real usage.
- Anything else (other modules'
src//tests/, the IntelliJ repository) counts as outside the module.
Tools to run the search:
- Within the Kotlin project: use
mcp__idea__search_text(preferred for exact names) ormcp__idea__search_regex,
with the paths parameter to scope the search. To distinguish own-tests from outside-the-module hits, run two queries (or read each result's path). For example, for a declaration in analysis/low-level-api-fir/, an "outside" search is:
paths: ["!analysis/low-level-api-fir/**"]…and an "own tests" search is:
paths: ["analysis/low-level-api-fir/tests/**", "analysis/low-level-api-fir/testFixtures/**"]- Within the IntelliJ repository: the IntelliJ repo is a separate project, so JetBrains MCP cannot search it. Use the
standard Grep tool against --intellij=<path>. Anything that hits in the IntelliJ repo counts as outside the module. If the path doesn't exist, notify the user but don't abort — proceed with Kotlin-repo results only.
Reducing false positives:
- For declarations with common names (
create,get,resolve), search for the qualified name or a distinctive usage
pattern (e.g., ClassName.methodName, import ...ClassName).
- When a hit is ambiguous, read the usage site to confirm it references this specific declaration.
- Classifier names (classes/interfaces/objects) are usually distinctive enough on their own.
Step 3: Apply the per-declaration decision
| Test's suggestion | Where the declaration is referenced (besides own src/) | Action |
|---|---|---|
@KaImplementationDetail | Nowhere (only own src/) | Downgrade. Remove the inserted annotation line. Add internal before the declaration keyword. |
@KaImplementationDetail | Anywhere else (own tests, outside the module, IntelliJ) | Keep. No change. |
@LLFirInternals | Nowhere (only own src/) | Downgrade. Remove the inserted annotation line. Add internal before the declaration keyword. |
@LLFirInternals | Only inside analysis/low-level-api-fir/ (own tests/testFixtures, no usages outside) | Keep. No change. This is precisely what @LLFirInternals is for: making a src/ declaration accessible to LL FIR's own tests. |
@LLFirInternals | Anywhere outside analysis/low-level-api-fir/ | Upgrade. Replace the @LLFirInternals line with @KaImplementationDetail. Swap imports accordingly. |
Apply edits with mcp__idea__replace_text_in_file. Import housekeeping: when removing or replacing an annotation, also remove the corresponding import if no other declaration in the file still uses it. When adding @KaImplementationDetail, ensure import org.jetbrains.kotlin.analysis.api.KaImplementationDetail is present.
Companion-object exception. A companion object's marker must match its outer classifier's final marker. The companion is reached through the outer class (Outer.member → Outer.Companion.member), so callers who can opt into the outer must also reach the companion. Skip the usage analysis for companion objects in the diff entirely; instead, decide the outer first using the table above, then sync the companion:
- Outer kept as
@KaImplementationDetail→ companion stays@KaImplementationDetail. - Outer kept as
@LLFirInternals→ companion stays@LLFirInternals. - Outer upgraded to
@KaImplementationDetail→ upgrade the companion the same way (replace@LLFirInternalswith
@KaImplementationDetail, swap imports).
- Outer downgraded to
internal→ drop the companion's annotation (Step 4 below).
Step 4: Downgrading nested classifiers
If the same diff includes a top-level classifier and nested classifiers within it, and the top-level was downgraded to internal, the nested classifiers don't need their own marker — Kotlin's internal visibility transitively covers them. For each nested classifier in the diff under that newly-internal parent: drop the inserted annotation (and any redundant import), without adding internal.
The skill does not need to handle override declarations specially: the codebase test's isViolation filters them out before they reach the diff (see AbstractAnalysisApiInternalApiTest.isViolation).
---
Phase 3: Verify
Run JetBrains MCP get_file_problems with errorsOnly=false on the modified file. Fix any warnings or errors related to the changes (missing imports, opt-in requirements introduced by the new annotations, etc.).
---
Phase 4: Loop
Re-run Phase 1 Step 1 with the same flags. There are three outcomes:
- Test passes → proceed to Phase 5.
- Test fails on the same file you just processed → something went wrong (the downgrade/upgrade may have re-introduced a
violation, or the file still has unmarked declarations). Stop and report to the user.
- Test fails on a new file → return to Phase 2 with that file.
---
Phase 5: Build and report
Run a normal compilation of the module:
./gradlew :analysis:<module>:compileKotlin -qIf the build succeeds, proceed to Phase 6.
If the build fails, stop and present the errors verbatim to the user for manual review. The skill does not auto-fix build errors. Common failure modes the user will need to resolve:
- "internal declaration exposed through public API" — a declaration the skill downgraded to
internalis referenced
in the signature of a public declaration in the same module. The user typically resolves this by switching the exposed declaration from internal to @KaImplementationDetail.
- `OPT_IN_USAGE_ERROR` at use sites — a callsite of a newly annotated declaration needs an
@OptInannotation, a
module-level optIn compiler option, or its own marker annotation. These can also be triggered by previously unannotated declarations the test just marked.
- Unresolved imports — rare, but possible if the skill's import housekeeping in Phase 2 missed a case.
Auto-fixing any of these from the diff alone risks masking real problems (e.g., upgrading internal to @KaImplementationDetail everywhere on exposure would defeat the point of distinguishing the two), so this is left for manual review.
---
Phase 6: Final summary
Present a per-classification breakdown:
- Declarations marked
internal(Phase 2 downgrades). - Declarations kept as
@KaImplementationDetail(test's suggestion confirmed). - Declarations kept as
@LLFirInternals(own-tests-only access; no usages outsideanalysis/low-level-api-fir/). - Declarations upgraded from
@LLFirInternalsto@KaImplementationDetail(Phase 2 upgrades). - Any compilation errors flagged in Phase 5 for the user to resolve manually.
Related skills
FAQ
What does analysis-api-mark-internal-apis do?
analysis-api-mark-internal-apis skill documents Drive the per-module internal-API codebase test, then refine the suggested annotations down to `internal` (or up to `@KaImplementationDetail`) based on actual external usage.
When should I use analysis-api-mark-internal-apis?
User asks about analysis-api-mark-internal-apis, drive the per-module internal-api codebase test, then refine the suggested annotations dow.
Is this skill safe to install?
Review the Security Audits panel on this page before installing in production.