agentleFS
JetBrainsKnown publisherJetBrains/mcp-steroid/CLAUDE.md

mcp-steroid

CLAUDE.md82 starsChanged 3 months agoApache-2.0View on GitHub

Guidance for Claude Code when working with this repository. Instructions here override default behavior. Three tenets govern every change in this repo — to code, MCP tools, or prompts. Read docs/PHILOSOPHY.md (mirrored as mcp-steroid://skill/design-philosophy for runtime fetch via steroid_fetch_resource) before proposing any of: Short version: the MCP tool surface (8 today) stays narrow on purpose; the IntelliJ capability surface stays full, exposed via steroid_execute_code plus prompt resources. The strategy page's "Give AI the whole IDE, not just the files" is…

  • Commits and pushes

1 other project uses a version of this.

Adopted by

Most recently taken up by

The file

Show its rules and text

We split this CLAUDE.md into the rules it gives an agent

23 rules. About 0 are common, 9 are distinctive, and 14 are very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈9

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 14

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Distinctive:

    Before acting on any task that touches files in a sub-folder, walk the directory tree from the changed file's folder up to the project root …

    line 26
  2. Distinctive:

    When changing files across multiple sub-folders, read the guides for each.

    line 46
  3. Very specific:

    Use IntelliJ MCP for everything where you can — see ij-plugin/CLAUDE.md for the API patterns.

    line 63
  4. Distinctive:

    Never ignore warnings or errors — fix them properly.

    line 64
  5. Very specific:

    No test-only branches (isUnitTestMode) — use correct IntelliJ actions (writeIntentReadAction, writeCommandAction).

    line 65
  6. Distinctive:

    Prefer JSON libraries for JSON parsing/manipulation.

    line 68
  7. Distinctive:

    Never include AI as co-author or mention AI in commit messages.

    line 71
  8. Very specific:

    The internal visibility modifier: Prefer plain public (no modifier).

    line 77
  9. Very specific:

    Never COPY or chmod +x it inside Dockerfiles.

    line 85
  10. Distinctive:

    Infrastructure workarounds in tests: When a test fails due to missing Docker socket, missing CLI, wrong JDK, or missing native library, fix …

    line 94
  11. Very specific:

    Do not use UsefulTestCase.shouldRunTest() for this: it silently reports the test as passed-without-running, hiding that the coverage never …

    line 110
  12. Very specific:

    Never assert contains("some/relative/path") against a message that embeds Path.toString() — build the expected fragment with …

    line 145
  13. Very specific:

    Never assert a raw Path.toString() substring against output that re-encodes the value as JSON: Windows backslashes arrive JSON-escaped …

    line 151
  14. Very specific:

    Prose-only prompt edits need only the contract test: When a change under prompts/src/main/prompts/ touches no kotlin fence, run ./gradlew …

    line 194
  15. Distinctive:

    Read requirements; ask if ambiguous.

    line 247
  16. Distinctive:

    Add a failing test, then implement (test-first.

    line 248
  17. Very specific:

    Run Gradle build/test via the IDE's MCP, not shell — see ij-plugin/CLAUDE.md for the run-config recipe.

    line 249
  18. Very specific:

    Test with IntelliJ MCP. Validate full Docker scenarios via :test-integration:test / :test-experiments:test.

    line 251
  19. Very specific:

    Use steroid_execute_code to verify warnings/errors are gone before declaring done.

    line 252
  20. Very specific:

    Update TODO* and commit.

    line 253
  21. Very specific:

    Never advance website while VERSION on main has no matching *published* GitHub release — gate the push with …

    line 315
  22. Very specific:

    origin → jb: always via merge (the jb-merge procedure below).

    line 327
  23. Distinctive:

    jb → origin: always via cherry-pick (individual commits, manual conflict resolution).

    line 328

≈ “Common” is an estimate: at least 1 in 5 of the 26,980 CLAUDE.md files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
CLAUDE.md

CLAUDE.md, AGENTS.md

Guidance for Claude Code when working with this repository. Instructions here override default behavior.

Design philosophy

Three tenets govern every change in this repo — to code, MCP tools, or prompts. Read docs/PHILOSOPHY.md (mirrored as mcp-steroid://skill/design-philosophy for runtime fetch via steroid_fetch_resource) before proposing any of:

  • a new steroid_* MCP tool
  • a new method on McpScriptContext
  • a "helper" that wraps an IntelliJ API

Short version: the MCP tool surface (8 today) stays narrow on purpose; the IntelliJ capability surface stays full, exposed via steroid_execute_code plus prompt resources. The strategy page's "Give AI the whole IDE, not just the files" is delivered through that combination — steroid_execute_code reaches every IDE API, and the mcp-steroid:// prompt corpus teaches the agent how. New tools and new context methods are not the lever.

Recursive context lookup (do this before sub-folder work)

Before acting on any task that touches files in a sub-folder, walk the directory tree from the changed file's folder up to the project root and read every CLAUDE.md and AGENTS.md you find on the way (including this one). Sub-folder guides take precedence over the root for their own scope; the root only holds project-wide rules.

Recipe (run this in your head, or with a one-liner). Normalize the starting directory to an absolute path first — relative paths converge on . and never match the repo root, infinite-looping:

# from any file path (relative or absolute), walk parents to repo root, collecting CLAUDE.md / AGENTS.md
file="<changed-file>"
dir=$(cd "$(dirname "$file")" && pwd)
root=$(git rev-parse --show-toplevel)
while [ "$dir" != "$root" ] && [ "$dir" != "/" ]; do
  for f in CLAUDE.md AGENTS.md; do [ -f "$dir/$f" ] && echo "$dir/$f"; done
  dir=$(dirname "$dir")
done
for f in CLAUDE.md AGENTS.md; do [ -f "$root/$f" ] && echo "$root/$f"; done

When changing files across multiple sub-folders, read the guides for each.

Sub-folder guides

FolderGuideScope
ij-plugin/ij-plugin/CLAUDE.mdIntelliJ plugin code, services, threading, build, deployment, sandbox/index troubleshooting, registry keys
prompts/prompts/AGENTS.mdPrompt file format, IDE conditionals, mcp-steroid:// resources, KtBlocks
test-integration/test-integration/AGENTS.mdStable Docker IDE smoke tests, shared infra, hung-test diagnosis, multi-version compat tests, playgrounds, Rider/.NET, Linux Docker CI gotchas
test-experiments/test-experiments/CLAUDE.mdDPAIA arena suite, debugger demos, prompt-quality comparisons, IMPROVEMENTS.md harness
docs/docs/CLAUDE.mdAutoresearch / prompt-optimization working notes, DPAIA history
website/website/CLAUDE.mdHugo site sources, GitHub Pages deployment
installer-gen/installer-gen/CLAUDE.mdBuild-tooling: computed JDK data model (Corretto/Azul, PGP-verified, pinned fingerprints), on-disk download cache, install.sh/install.ps1 generation
website-gen/website-gen/CLAUDE.mdBuild-tooling generator: version.json + updatePlugins.xml (depends on :installer-gen for shared HTTP)

MUST DO

  • Use IntelliJ MCP for everything where you can — see ij-plugin/CLAUDE.md for the API patterns.
  • Never ignore warnings or errors — fix them properly.
  • No test-only branches (isUnitTestMode) — use correct IntelliJ actions (writeIntentReadAction, writeCommandAction).
  • Tests must show reality. Never remove, disable, or weaken a failing test; fix the underlying issue.
  • No @Suppress("DEPRECATION") — find the non-deprecated replacement.
  • Prefer JSON libraries for JSON parsing/manipulation; only static final JSON constants may be hand-written as raw strings.
  • Log new ideas/tasks in TODO* files (TODO.md, TODO-*.md).
  • Atomic commits with descriptive messages (what and why). Test and build before committing.
  • Never include AI as co-author or mention AI in commit messages.

Banned patterns

  • runCatching{}.onFailure{} — use try { } catch (e: Exception) { } instead. Other runCatching uses (.getOrNull(), .getOrDefault()) are fine.
  • The internal visibility modifier. Prefer plain public (no modifier). Don't add internal to declarations — including test-visible helpers.
  • Returning a (value, errorFlag) pair/tuple from a call that can fail. Return the value (or a domain value object) and signal failure by throwing or returning null — not Pair<Result, Boolean> where the boolean is an error/isError flag.
  • Empty catch / catch (_: Exception) {}. Fail fast and log: every catch must rethrow, log via System.err.println / logger.error, or both. Silent failure hides root causes.
  • run-agent.sh references in production code or tests. It is a manual dev/peer-review tool only. Never COPY or chmod +x it inside Dockerfiles. Implement agent integrations directly via CLI flags.
  • Cross-subproject build/ directory access in Gradle build files. Use Gradle dependency configurations. Fail fast with require()/error() — no silent fallbacks.
  • append("\n") tricks to bypass the NoLargeInlineStringsTest lint rule. When a buildString { } exceeds the consecutive-appendLine limit, move the content to prompts/src/main/prompts/ and reference it via the article URI.
  • Hardcoded mcp-steroid://... URI literals in production Kotlin. Use the generated article class: XxxPromptArticle().uri (from com.jonnyzzz.mcpSteroid.prompts.generated.*). Enforced by NoHardcodedMcpSteroidUriUsageTest. See FetchResourceToolHandler.kt.
  • Infrastructure workarounds in tests. When a test fails due to missing Docker socket, missing CLI, wrong JDK, or missing native library, fix the infrastructure — never add detection-and-skip code.
  • Detecting failures and skipping tests at runtime (try { } catch { skip() }, Assumptions.assumeTrue(isAvailable), TestAbortedException on error). The only acceptable skip is at the Gradle task level (enabled = !condition) when an entire suite is structurally incompatible with the platform.
    • Single documented exception: Gemini API key on CI. TC has no Gemini token and there is no plan to add one. DockerGeminiSession.Companion opts into skipTestWhenKeyMissing = true (see test-helper/.../AISessionBase.kt), so requireApiKey() throws AssumptionViolatedException instead of IllegalStateException when the key is missing — JUnit 4/5 runners report that as ignored. JUnit 3 / BasePlatformTestCase tests (e.g. CliGeminiIntegrationTest) get no skip from that assumption under the plain bridge — JUnit38ClassRunner.addError fires fireTestFailure for every Throwable, assumptions included (still true in JUnit 4.13.2) — so they must additionally run under @RunWith(JUnit38AssumeSupportRunner::class) (the IntelliJ test-framework runner that reroutes AssumptionViolatedException to fireTestAssumptionFailed, i.e. a real SKIPPED/ignored result) and gate runBare early on skipTestBecauseApiKeyMissing() so the skip costs no fixture/Docker setup. Do not use UsefulTestCase.shouldRunTest() for this: it silently reports the test as passed-without-running, hiding that the coverage never executed. Constraints when working in this area:
      1. Session creation must stay lazy — called from inside test method bodies, never from setUp() / class init / @ClassRule. BasePlatformTestCase-backed tests route every Throwable through JUnit38ClassRunner to fireTestFailure, so an early init failure shows up against the wrong test.
      2. Do NOT add excludeTestsMatching or other test-class-level filters — that hides the test from reports.
      3. Unresolved %credentialsJSON:…% must still fail hard with IllegalStateException — that branch indicates a real TC misconfiguration and must stay visible. The contract is unit-tested in :test-helper:test AIAgentCompanionApiKeyTest.
      4. Do NOT extend the opt-in to other agents. Anthropic / OpenAI keys ARE configured on TC; their tests must keep failing if the key disappears.
  • Java threading primitives (CountDownLatch, Semaphore, Object.wait()) in coroutine code. Use CompletableDeferred<T> + withTimeout(d) { deferred.await() }, Channel<T>, or suspendCancellableCoroutine.
  • ./gradlew test at the repo root. It fans out to every module and can take hours. Always scope: ./gradlew :ij-plugin:test, ./gradlew :kotlin-cli:test, ./gradlew :prompts:test --tests '<pattern>'. See per-module guidance in ij-plugin/CLAUDE.md.
  • Literal /* inside KDoc bodies. Kotlin doc comments support nested /* */, so a string like "`7z/win-x64/*`" in a /** */ block starts an inner comment; the next */ closes the INNER, leaving the outer open. The compiler reports Unclosed comment at the end of the file plus a cascade of unresolved-reference errors. Rewrite as // line comments or quote the substring to avoid the /* sequence.
  • Windows-hostile test fixtures and assertions. Five recurring shapes, all found live on the TC Windows agent (2026-08-05 #445 + the CliToolSupportTest CRLF round; 2026-08-07 the 0.102 release-week rounds, TC builds 629–630):
    1. Whole-string assertions on PrintStream output MUST normalize \r\n → \n in the capture helper (println uses the platform separator; the TC report renders expected/actual as visually identical). GeneratedToolRuntimeTestSupport is the reference implementation.
    2. File.setExecutable(false) is a silent no-op on NTFS and Files.isExecutable() stays true for any readable file — a "non-executable file" precondition is unrepresentable there. Use an injectable probe with a production default (see RemoteDevelopmentLauncherResolver's isExecutable seam), never chmod-based fixtures.
    3. Never assert contains("some/relative/path") against a message that embeds Path.toString() — build the expected fragment with Path.of("some", "relative", "path").toString().
    4. A Unix-style fixture like Path.of("/home/u") is NOT drive-absolute on Windows: any production path that goes through toAbsolutePath()/normalize() gains the current drive (Z:\home\u) and the equality fails. Use a temp-dir fixture (@TempDir, Files.createTempDirectory) — it is genuinely absolute on every OS (HomePathsTest, DevrigSetupTest are the references).
    5. Never assert a raw Path.toString() substring against output that re-encodes the value as JSON: Windows backslashes arrive JSON-escaped (Z:\\dir). Compare against JsonPrimitive(value).toString() instead (ScreenshotAndOpenProjectCommandTest). Diagnosing a red Windows leg: without --continue, the first failing module's test task stops later modules — compare the leg's total test count against the Linux leg; a large shortfall means more Windows-hostile tests hide behind the reported ones (the 629→630 "onion": fixing 1 exposed 3). The NEW-failure surface is exactly the test files changed since the last green Windows run.
  • Snapshotting /proc/<pid>/cmdline (ProcessHandle.info().arguments()) right after a spawn. On Linux a spawned child execs IN PLACE through jspawnhelper → setsid → env → sh before becoming the target binary; a one-shot read races that chain and sees "sh" or an empty Optional (broke mcp_steroid_DevrigTest deterministically on cold TC agents). Poll with withTimeout { while (...) delay(...) } until the expected command appears. Identity checks must use exec-stable properties (pid + startInstant), never the cmdline.
  • MCP stdio scripts writing to stdout. Any shell/PowerShell wrapper invoked by an agent CLI as a stdio MCP server (devrig mcp, etc.) must emit only stderr before exec-ing the inner binary. Stdout is the JSON-RPC channel — a single stray byte corrupts the protocol. Use >&2 (POSIX) or Write-Error / [Console]::Error.WriteLine (PowerShell).
  • claude mcp add without --scope user. The Claude CLI defaults to --scope local, which writes to claude.json.projects.<cwd>.mcpServers instead of the top-level user-scope mcpServers. Registration is then invisible from any other project. All user-wide Claude mcp add calls must pass --scope user. Codex and Gemini default to global/user-wide and do not need the flag.
  • Materializing files for Gradle's daemon classpath at CONFIG phase. Anything that needs to be on the gradle daemon's classloader during config phase (e.g., resources read by :ij-plugin's IPGP local(provider) at task-graph time) must be pre-staged in settings.gradle.kts — buildSrc is chicken-and-egg (its tasks don't run until after settings + buildSrc itself), and main-project task outputs are too late. See gradle/seven-zip-bootstrap.settings.gradle.kts for the canonical example (commit 0b7bbe78).

Test execution discipline

  • NEVER run :test-integration or :test-experiments tests in parallel. Each test starts a full Docker IntelliJ container. Two concurrent runs exhaust RAM/CPU and OOM-kill both. Wait for completion before starting the next. See test-integration/AGENTS.md for the full Docker-test playbook.
  • Diagnose stuck/slow tests with JDK tooling BEFORE killing. jps -l | grep GradleWorkerMain → jcmd <pid> Thread.print > /tmp/dump.txt while the JVM is alive; then grep '<YourTest>Test' /tmp/dump.txt -A 5. Killing throws away evidence and forces guess-and-retry. Once you have the stuck test's name, iterate on just that test (--tests 'com.example.StuckTest'
    • --rerun-tasks).
  • Prose-only prompt edits need only the contract test. When a change under prompts/src/main/prompts/** touches no ```kotlin fence, run ./gradlew :prompts:test --tests '*MarkdownArticleContract*' (seconds). The *KtBlock* compilation matrix recompiles every fence against every unpacked IDE (60–120 min) and is only needed when kotlin fences change — never run it casually (a workflow agent once hung 37 min on it for a prose edit).
  • 1-minute rule for integration tests. Any :test-integration / :test-experiments case that hasn't printed PASS/FAIL within ~60 s of > Task :*:test is suspicious — usually a modal dialog, indexing stall, or background task that won't finish. Capture the latest screenshot (ls -t test-integration/build/test-logs/test/run-*/screenshot/*.png | head -1) and an in-container thread dump (docker exec <id> jcmd <PID> Thread.print) before deciding. Full recipe and symptom→cause table in test-integration/AGENTS.md → "Debugging a stuck/hung Docker test".

Project Overview

devrig is the product — the CLI you install and run. One command installs devrig with its own bundled runtime (no manual setup); devrig install <agent> wires it into Claude Code, Codex, or Gemini. To reach real IDE semantics, devrig talks to MCP Steroid, the IntelliJ Platform plugin that exposes a standalone MCP server letting LLM agents drive the IDE via Kotlin code execution — installed in your JetBrains IDE as well (JetBrains Marketplace).

  • Public repo: https://github.com/jonnyzzz/mcp-steroid
  • Docs: README.md, docs/guides/AGENT-STEROID-GUIDE.md
  • Modules: see settings.gradle.kts. Plugin code lives in ij-plugin/; prompt resources in prompts/; Docker IDE smoke tests in test-integration/; experimental/long-running tests in test-experiments/.

devrig CLI contributor contract

docs/devrig-cli-contract.md is authoritative for command grammar, help, human/JSON output, direct MCP-tool commands, and open_project --wait. Keep one Clikt parser and derive tool commands from their schemas. Use canonical list_projects; projects and project are compatibility aliases. Missing/invalid parameters must route to focused help with allowed values, and parse validation must happen before backend, file/stdin, or --out side effects. Agent-facing changes require the unit, stable Docker, and Claude/Codex experiment buckets named in that contract.

Technology Stack

Gradle 9.6.1 / Kotlin 2.3.20 / Java 25 toolchain / IntelliJ Platform 2026.1+ / Ktor 3.3.2 (CIO+SSE) / kotlinx.serialization

Bytecode targets Java 21 (class-file v65) while the toolchain stays JDK 25: Android Studio 2026.1 bundles JBR 21 (IDEA bundles JBR 25), so the plugin must load on both. Set via the root subprojects {} convention (jvmTarget=21 + -Xjdk-release=21 + options.release=21); enforced by verifyClassFileVersions on the plugin/devrig distributions; regression-gated by AndroidStudioRuntimeCompatTest. See issue #157.

The Gradle Daemon is pinned to JDK 25 via gradle/gradle-daemon-jvm.properties (matches IDEA 2026.1's bundled JBR — see docs/262-EAP-PLAN.md). The foojay-resolver-convention plugin in settings.gradle.kts is the auto-download fallback if no JDK 25 is present locally. To change the daemon JVM: edit gradle-daemon-jvm.properties directly (one-line toolchainVersion=N).

Workflow

  1. Read requirements; ask if ambiguous.
  2. Add a failing test, then implement (test-first; integration tests preferred; never fake tests).
  3. Run Gradle build/test via the IDE's MCP, not shell — see ij-plugin/CLAUDE.md for the run-config recipe.
  4. Deploy: ./gradlew deployPlugin.
  5. Test with IntelliJ MCP. Validate full Docker scenarios via :test-integration:test / :test-experiments:test.
  6. Use steroid_execute_code to verify warnings/errors are gone before declaring done.
  7. Update TODO* and commit.

CI

Root build.gradle.kts defines ci-prefixed aggregator tasks for TeamCity and GitHub Actions. ./gradlew tasks --group ci lists them.

TaskSubprojectsNotes
buildPluginOnCI:ij-plugin (builds + publishes ZIP)Entry point for both GH Actions and TC
ciBuildPluginTestsAll plugin modules except prompts + non-pluginPer-OS matrix on TC; includes verifyPlugin + bundled-library gates
ciBuildPromptsTestsprompt-generator, prompts, prompts-apiLinux only; full matrix takes 60–120+ min
ciIntegrationTests:test-helper:test → :installer-gen:installerIntegrationTest → :ij-plugin:integrationTest → :test-integration:testStrict sequential ordering via mustRunAfter; needs Docker + API keys
ciDevrigTests:npx-kt:test → :npx-kt:integrationTestdevrig unit + stdio Docker suite; Linux TC config, plus a Windows unit-only TC leg (:npx-kt:test — the real-NTFS BinLauncherWindowsTest runs nowhere else)
ciAgentLaunchTests:test-integration-agent-launch (test + windowsPs1Test)Cross-OS agent-launch behaviour; task-level OS gates (no-op on macOS)

:test-integration:test and :test-experiments:test have an onlyIf guard — plain root ./gradlew test silently skips both. Direct ./gradlew :test-integration:test --tests '...' still works. On TC, :test-integration:test is split by the mcp.testIntegration.lane property (main = smoke matrix, excludes playgrounds; compat = verifier/262-compat/Android-Studio legs on a fresh agent; unset = full suite, the local behavior) — see test-integration/AGENTS.md → "CI lane split".

On TeamCity, public Maven hosts route through the JetBrains cache redirector. The TC Mac farm (icri-big-agent-eqx-*) shares one NAT egress IP that Maven Central 429-rate-limits on cold resolution, and Gradle disables a repository for the whole build on the first transport error — the failing lookup was not even a repo dependency but buildSrc's kotlin-dsl → Gradle-distribution-pinned Kotlin, via the implicit Plugin Portal. gradle/jetbrains-cache-redirector.settings.gradle.kts (+ pluginManagement mirrors in both settings files) rewrites repo.maven.apache.org / repo1.maven.org / plugins.gradle.org to cache-redirector.jetbrains.com/<host>/<path>, gated on TEAMCITY_VERSION alone — GitHub Actions and local builds stay byte-identical. Only verified-mirrored hosts belong in that list (packages.jetbrains.team is NOT mirrored and stays direct).

Vendor-feed tests are opt-in, so a Google/JetBrains/GitHub outage can never redden a normal build:

TaskCoversCost
:npx-kt:liveNetworkTestevery supported IDE resolves off its live feed with a plugin-compatible build (live-network tag)~1 min, no archive download
:npx-kt:liveDownloadSmokeTestidea-community + android-studio really download, unpack and pass product-info.json validation (live-download tag)multi-GB per case
:intellij-downloader:liveNetworkTestproducts-API filename tokens still match (JUnit4 LiveNetwork category)seconds

The offline equivalent runs by default: AllIdeProductsDownloadTest walks every catalog product through recorded payloads of all three feeds.

TeamCity DSL lives in a separate repo (~/Work/mcp-steroid-teamcity). See its own CLAUDE.md for the generate→edit→regenerate→commit workflow, the build-configuration landscape (per-push VCS triggers on the gate configs, the Sunday-03:00 WeeklyAllTests composite, the CompatTests lane) and the jb tc CLI recipes for triggering/inspecting builds. The TC VCS root pulls from jb, not origin — see "Git remotes" below. When a DSL change passes a NEW Gradle property to this repo, land the property on jb/main FIRST: an unknown -P is silently ignored, so the config would quietly run the wrong scope.

GitHub Actions (.github/workflows/): builds the publishable plugin ZIP and deploys the website to GitHub Pages. Plugin tests are intentionally NOT mirrored — full coverage stays on TC (3–5× faster internal agents). Trigger PR builds via workflow_dispatch on the PR's head branch.

Website deploys from the website branch, NOT main. GitHub Pages builds on a push to the long-lived website branch (github-pages.yml). website tracks main (advance via git merge main → website, normally often) but can deliberately lag it so website changes that depend on an unreleased devrig binary — e.g. a new install.sh/install.ps1 CLI contract — stay off the live site until a matching GitHub release exists. The release process advances website AFTER publishing the release (release/release-instructions.md → "Stage 7c"). Advancing website is the devrig auto-update rollout trigger: the deploy regenerates version.json + the install scripts atomically, and devrig sessions auto-install off version.json (docs/updates-check/devrig-auto-update.md). Never advance website while VERSION on main has no matching published GitHub release — gate the push with release/scripts/verify-release-ready.sh. website is origin-only (never synced to jb, which runs TeamCity only). A push to main no longer deploys the website.

Git Remotes: origin vs jb

RemoteURLRole
origingit@github.com:jonnyzzz/mcp-steroidDay-to-day development fork; source of truth for new commits
jbgit@github.com:JetBrains/mcp-steroid.gitJetBrains-org mirror; consumed by TeamCity (mcp_steroid project)

Sync direction:

  • origin → jb: always via merge (the jb-merge procedure below).
  • jb → origin: always via cherry-pick (individual commits, manual conflict resolution).
  • Never fast-forward-push main to jb — jb/main carries org-specific commits that would be lost.
git fetch jb
git checkout -b jb-merge jb/main
git merge main --no-ff -m "Merge remote-tracking branch 'origin/main' into jb-merge"
git push jb jb-merge:main
git checkout main && git branch -D jb-merge

--no-ff preserves jb/main's existing head as the merge's first parent so jb-only history stays reachable. Why this matters for CI: TC pulls from jb. If your commit isn't on jb/main, TC builds stale code.

Push origin BEFORE jb-merging. Concurrent sessions push to origin/main constantly; a rejected git push origin main after the jb push already landed leaves jb ahead of the source of truth (hit twice on 2026-08-05). Recovery when it happens anyway: git pull --rebase origin main → git push origin main — the same change now exists under two SHAs (one on each remote), which is fine: the next jb-merge unifies identical content without conflict. Never cherry-pick it back.

No GitHub Actions on jb. The JetBrains-org mirror runs TeamCity only — it must carry no .github/workflows/ at all (those are origin/jonnyzzz-only: the GitHub Pages website deploy, PR compile gate, etc.). jb/main intentionally deletes every workflow file (e.g. commit "Delete .github/workflows/github-pages.yml"); that deletion is org-specific history to preserve. So during jb-merge, a modify/delete conflict on any .github/workflows/* file is expected whenever origin edits a workflow — always resolve by keeping it deleted on jb (git rm .github/workflows/<file> then commit the merge). Never resurrect a workflow onto jb.

IntelliJ Source Research

The IntelliJ project at ~/Work/intellij is open in the IDE for research. Use steroid_execute_code with project_name="intellij" and PSI APIs (FilenameIndex, JavaPsiFacade) — faster and more accurate than grep. See test-integration/AGENTS.md → "Researching IntelliJ APIs" for the recipe.

run-agent.sh from ~/Work/jonnyzzz-x/ launches AI agents (Claude/Codex/Gemini) for peer reviews, research, and consensus checks. Encouraged from agent sessions — the BANNED rule applies only to production code/tests referencing it. Usage: run-agent.sh <agent> <cwd> <prompt-file>; the default hard timeout is 900 s — deep reviews need RUN_AGENT_TIMEOUT_SECONDS=2700 (the env var is RUN_AGENT_-prefixed; a bare TIMEOUT_SECONDS is silently ignored).

Environment Constraints

timeout / gtimeout are not available on this Mac. Use Gradle's own timeout mechanisms or the Bash tool's timeout parameter.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.