From Beginner to Advanced Issues

This roadmap is a deliberately ordered ladder of OpenSearch contributions. Each rung trains one skill, depends on the rung below it, and ends at a concrete, review-ready Pull Request on github.com/opensearch-project/OpenSearch. Skipping rungs is the most common reason contributors stall: a shard-allocation fix without cluster-state fluency turns into a six-month PR thread, and a release-blocker triage call without backward-compatibility reflexes turns into a reverted commit on a release branch.

OpenSearch is not Apache. There is no JIRA, no patch attachments, no "Patch Available" state. The source of truth is GitHub: issues and Pull Requests. Contributions require a DCO sign-off (git commit -s), not a CLA. Every PR adds a one-line CHANGELOG.md entry. CI runs through GitHub Actions and Jenkins; the local pre-flight is ./gradlew precommit. If you are arriving from the Apache Tez roadmap, unlearn the JIRA muscle memory now — the rest of this section assumes the GitHub flow.

The stages are calibrated to the OpenSearch main / 3.x codebase. The maintenance line is 2.x; 1.x is legacy. Where a stage references real modules it uses the exact top-level paths you will see in a checkout:

server/                 the core engine. org.opensearch.* — the bulk of what you read
libs/                   low-level shared libs: libs/core (StreamInput/Output, Writeable),
                        libs/x-content (XContent parsing), libs/common, libs/geo
modules/                bundled-by-default modules: transport-netty4, reindex,
                        lang-painless, analysis-common, ingest-common, percolator
plugins/                in-repo optional plugins: analysis-icu, repository-s3, store-smb
client/                 Java clients: client/rest, client/sniffer
distribution/           packaging: archives, docker, deb/rpm, distribution/tools
test/framework/         OpenSearchTestCase, OpenSearchIntegTestCase, InternalTestCluster
qa/                     cross-version BWC, rolling-upgrade, mixed-cluster, packaging QA
rest-api-spec/          REST API JSON specs + shared REST-YAML tests (yamlRestTest)
benchmarks/             JMH microbenchmarks (:benchmarks)
buildSrc/, build-tools*/  Gradle build logic and custom plugins

Note: OpenSearch renamed the master node role and many APIs to cluster manager for inclusive language. The old terms survive as deprecated aliases (master role, cluster.initial_master_nodes). This roadmap writes "cluster manager (formerly master)" on first use in each stage and prefers the new term thereafter.


The Twelve Stages

#StageTarget skillPrereq levelPrimary subsystemTypical PR size
1Docs & testsGitHub flow, DCO, CHANGELOG, precommitnonedocs, test/framework1–40 lines
2Build, dependency & loggingversion catalog, Spotless, forbidden-APIs, Log4j21buildSrc, server5–80 lines
3Error messages & diagnosticsvalidate(), exception text, REST rendering2server/.../action, rest20–200 lines + test
4Cluster state & coordinationupdate tasks, appliers, listeners3org.opensearch.cluster30–300 lines + test
5Shard allocationAllocationDecider, RoutingAllocation4cluster.routing.allocation40–400 lines + test
6Indexing & engineIndexShard, InternalEngine, Translog, seqno4index.engine, index.translog50–500 lines + test
7Search & aggregationsQueryPhase, FetchPhase, InternalAggregation.reduce4search, search.aggregations50–500 lines + test
8Plugin & extension compatextension points, SPI, Plugin evolution4–7org.opensearch.plugins + plugin reposvaries; often two repos
9Flaky teststests.seed, assertBusy, @AwaitsFix, races4test/framework, *IT20–150 lines
10PerformanceJMH, OpenSearch Benchmark, GC/allocation, BigArrays6 or 7hot paths in server30–300 lines + bench
11Backward compatibilityVersion-gated streams, Lucene/index BWC, qa/4libs/core, qa/small code, long thread
12Release-blockingtriage, milestones, reverts, backportsmaintainerwhole-projectvaries

Stages 4–7 share a prerequisite level rather than a strict order: once you have cluster- state fluency (Stage 4) you can branch into allocation, engine, or search depending on the bug in front of you. Stage 8 sits across that band because the core↔plugin boundary touches whichever subsystem the extension point belongs to.


How OpenSearch labels map to stages

OpenSearch issues are labelled on GitHub. There is no JIRA component tree; instead a combination of type labels, status labels, and component/area labels does the same job. Learn these — every stage's issue search is built from them.

LabelMeaningWhich stages use it
good first issuecurated, small, mentor-friendly1, 2
help wantedmaintainers want community to take itall stages
untriagednot yet labelled by a maintainer; do not start blindfilter these out until triaged
bugincorrect behaviour3–8, 11, 12
enhancementnew behaviour / improvement2, 3, 7, 10
flaky-testa test that fails nondeterministically9
discuss / RFC / proposal / metadesign-level, needs a thread firstnot bug-fix work; read, don't patch
backport 2.x, backport 1.xtriggers the backport bot when merged11, 12
v3.x.0 (milestone, not a label)targeted release12
Component/area labelsCluster Manager, Search:Aggregations, Storage:Durability, Indexing, Search:Performance, Plugins, distributed frameworkevery stage scopes by these

The component labels drift and get renamed; do not memorise the exact strings. Instead, open https://github.com/opensearch-project/OpenSearch/labels once and skim the current set, then use the label:"…" filter that the relevant stage shows. Every stage also gives at least one fallback grep to find a candidate when labels return nothing.

A canonical issue search, reused (with different labels) in every stage:

is:issue is:open label:"good first issue" label:"help wanted" no:assignee sort:updated-desc

Paste it into the GitHub issue search box on the OpenSearch repo. no:assignee is the single most useful filter: it skips issues someone is already on.


How to use this roadmap

Pick a stage honestly

Find your rung by asking what is the largest change you have shipped to OpenSearch:

  • Never landed an OpenSearch PR: start at Stage 1.
  • Landed a docs PR but never touched Java in server/: Stage 2.
  • Comfortable with server/ Java but never read a cluster-state update task: Stage 3.
  • Read ClusterApplierService once and were confused: Stage 4.
  • Read it twice and could draw the publish/apply flow: Stages 5–7.
  • Already a maintainer (in a MAINTAINERS.md): jump to Stages 10–12 for sharpening.

Do not jump rungs to chase a "cool" bug. A wrong Decision in DiskThresholdDecider looks self-contained and isn't — the fix lands on RoutingAllocation plumbing and a ClusterInfo you have never built in a test (Stage 4 prerequisite work).

One stage per PR

Resist the urge to fix two things in one PR. OpenSearch reviewers reject mixed-concern PRs almost reflexively, and the CHANGELOG entry forces you to name the single change in one line — if you cannot, the PR is doing too much. If you find a logging issue while fixing an error message, open a follow-up issue and move on. The roadmap rewards small surface area.

Always start with git log and git blame

Before touching a file, find who cares about it:

git log --oneline -n 5 -- server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java
git blame -L 200,260 server/src/main/java/org/opensearch/cluster/service/ClusterApplierService.java

The blame output tells you which maintainer last touched that region. Mention them with @handle in your PR description (politely, once) — that is how OpenSearch routes review, in place of CC-ing a mailing list.

Read the workflow once, then never re-explain it

Every stage from 2 onward assumes the Stage 1 mechanics: fork → branch → DCO sign-off → CHANGELOG entry → ./gradlew precommit → PR → read CI → respond to review. Stage 1 drills all of it. The later stages spend their words on code, not process.

Time investment per stage

Calibrated against a contributor who has the repo checked out, can run ./gradlew localDistro and ./gradlew :server:test, and has opened at least one PR:

StageFirst PRBecoming fluent (≈5 PRs merged)
1half a day1 week
21 day2 weeks
31–2 days1 month
43–5 days2–3 months
51–2 weeks4–6 months
62–4 weeks6 months
72–4 weeks6 months
81–3 weeks per boundarya year of cross-repo work
91–3 days per flakeongoing
10weeks (perf is bench-bound)maintainer-level skill
11weeks (BWC review cycle)maintainer-level skill
12maintainer responsibilityn/a

Success criterion per stage

Each stage is "complete" for you when:

  • Stage 1: one docs/javadoc PR and one test-only PR are merged.
  • Stage 2: two logging or build/dependency PRs merged without precommit re-asks.
  • Stage 3: one error-message PR merged with a unit test asserting the exact text.
  • Stage 4: one cluster-state fix merged with a ClusterServiceUtils-based test.
  • Stage 5: one allocation fix merged, reproduced via a RoutingAllocation unit test.
  • Stage 6: one engine/translog fix merged with an InternalEngineTests-style test.
  • Stage 7: one search/agg fix merged with an AggregatorTestCase/AbstractQueryTestCase test.
  • Stage 8: one core change merged that you verified against a real plugin build.
  • Stage 9: at least three flaky tests de-flaked (un-muted and fixed).
  • Stage 10: one perf PR merged with before/after JMH or OSB numbers.
  • Stage 11: one BWC-sensitive PR merged with a Version guard and a qa/ test.
  • Stage 12: you have helped triage at least one release-blocking issue.

When to open a discuss issue first

For Stages 4 and above, before writing code, open (or comment on) the GitHub issue with a three-sentence plan:

I see <symptom> at <file> (grep below). My read is <cause>. I plan to <fix>, with a
regression test in <TestClass>. Anything I'm missing before I open a PR?

The maintainers will tell you within a day or two whether you are about to collide with in-flight work or a design decision. This is the GitHub equivalent of the Apache [DISCUSS] dev@ ping — same discipline, different venue.


What to read alongside this roadmap


What this roadmap is not

This roadmap is not a tutorial on OpenSearch itself. The deep dives cover the architecture; the labs from Level 1 onward cover hands-on code reading. The roadmap assumes you can already build from source, run ./gradlew :server:test, and stand up a node with ./gradlew run. If you cannot, the prerequisite is Level 1.

It is also not a generic open-source guide. CONTRIBUTING.md, DEVELOPER_GUIDE.md, and TESTING.md in the repo cover account setup, the DCO mechanics, and the test commands; the roadmap assumes you have read them once.

Finally, it is not a roadmap to maintainership. Becoming a maintainer is a separate path the TSC and each repo's existing maintainers manage (see the maintainer mindset). The roadmap teaches the skills that, applied consistently, make maintainership a reasonable outcome — landing PRs is necessary, not sufficient.


How the stages interlock

Each stage builds vocabulary the next stage uses without re-explaining:

  • Stage 1 teaches the PR artifact: fork, DCO, CHANGELOG, precommit. Every later stage assumes it.
  • Stage 2 teaches Log4j2 idioms and the build gates. Stage 3 builds on them with the rule that every thrown exception carries actionable context.
  • Stage 3 teaches you to navigate the action/rest layer. Stage 4 follows the request into the cluster-manager service and its update tasks.
  • Stage 4 teaches ClusterState, update tasks, and appliers. Stages 5–7 all read cluster state: allocation routes shards, the engine reacts to index metadata, search resolves shards from the routing table.
  • Stage 5 teaches RoutingAllocation unit tests. Stage 6 teaches InternalEngineTests. Stage 7 teaches AggregatorTestCase. These three test harnesses are the workhorses of core contribution.
  • Stage 8 teaches the plugin boundary, attributing a break to core vs a plugin — the OpenSearch analog of the Tez "Hive-on-Tez" attribution skill.
  • Stage 9 teaches deterministic testing (tests.seed, assertBusy). Stage 10 uses that determinism as the baseline for stable benchmarks.
  • Stage 10 teaches measurement. Stage 11 uses measurement as evidence in BWC decisions. Stage 11 teaches Version gating, which Stage 12 weighs when deciding whether an issue blocks a release or merely a backport.

Skipping a stage means skipping a vocabulary. Reviewers will notice.

Now turn to Stage 1.