Skip to main content

n3Plugins AI Agent Handbook

Use this handbook when you build or review n3 API, SDK, or plugin work. It applies to human contributors and coding agents. Live source is the authority. Use this page to keep changes aligned with the repo.

Authority Order

  1. Live source under src/main/java and src/test/java.
  2. N3PLUGINS_SOURCE_OF_TRUTH.md for current registration, packages, action catalog, dependencies, validation, and runtime ownership.
  3. AGENTS.md and local agent prompts.
  4. Plugin docs under docs/.
  5. RuneLite client and API Javadocs when a callback, widget, or API contract matters.

Passing tests do not prove live RuneLite behavior. Mark live behavior pending until you observe it in the client.

Operating Rules

  • Inspect git status --short --branch and relevant diffs before editing.
  • Read AGENTS.md, N3PLUGINS_SOURCE_OF_TRUTH.md, and the docs for the area you touch.
  • Use CodeGraph for structural discovery. Use rg for literal text, configuration, and documentation searches, then read only the focused files.
  • Keep changes scoped to the request. Avoid hidden refactors and tool-generated artifacts.
  • Import Java types and use simple names in source. Keep fully qualified names inline only when two required types have the same simple name.
  • State file-writing side effects before creating workflow files, screenshots, local harness output, or generated reports.
  • Use InteractionApi.actions.* for new game interactions. Return and inspect InteractionResult.
  • Use sdk.* helpers before adding plugin-local equivalents.
  • Add source Javadocs for public declarations under InteractionApi and sdk. ApiJavadocCoverageTest checks coverage and rejects placeholder wording.
  • Do not add suite-level walker or pacer tick owners. PacketUtilsPlugin.onGameTick owns ActionPacer.onTick(...), bootstrap, and Walker.tick().
  • Logged-in automation that requires account setup calls PacketUtilsPlugin.requireAccountBootstrap(owner) while active, gates gameplay actions on the returned readiness, and releases the owner when idle or stopped. Passive overlays and bookkeeping may run outside that gate.

Repo Orientation

AreaSourceUse it for
Shared plugincom.n3plugins.PacketUtilsRevision setup, packet reflection, SDK init, bootstrap, pacer tick, walker tick, plugin-list branding
Action APIcom.n3plugins.InteractionApi.actionsResult-aware interaction calls
Resultscom.n3plugins.InteractionApi.commonInteractionResult, InteractionStatus, guards, matchers
Planningcom.n3plugins.InteractionApi.planTaskPipeline, TaskStep, StepResult, InventoryPlan, cooldown helpers
Pacingcom.n3plugins.InteractionApi.pacingSuite-wide action pacing and diagnostics
Debugcom.n3plugins.InteractionApi.debugSuiteRuntimeStatus, WidgetExplorer, PacketTrace, revision health checks
Widgets and itemscom.n3plugins.sdk.widgetsWidget, inventory, bank, equipment, dialogue, shop, GE, rune-pouch helpers
Queriescom.n3plugins.sdk.queryInventory, bank, equipment, NPC, player, object, item, widget, trade, and shop filters
ID mapscom.n3plugins.sdk.idmapsBundled and revision-cache ID map lookup
Walkercom.n3plugins.sdk.walkerPath planning, route handles, collision, transports, requirements
Loadoutscom.n3plugins.sdk.loadoutsInventory and equipment targets
Workflowcom.n3plugins.sdk.workflowAutomationApi, AutomationStateMachine, domain workflow builders
UIcom.n3plugins.uiN3Theme, N3PluginPanel, cards, buttons, bundled brand asset

For the full action catalog, use the SOT action table first, then open the matching class under InteractionApi.actions.

API Mapping Flow

  1. Write the workflow state or user action in plain terms.
  2. Search InteractionApi.actions.* for a result-aware action class.
  3. Search sdk.* for a shared widget, query, walker, loadout, or workflow helper.
  4. Use GameVars for raw varbit or varplayer reads when no action class owns the state.
  5. Use RuneLite API directly only when no n3 layer covers the operation.
  6. If more than one plugin would need a missing helper, add it to the shared SDK. If only one plugin needs it, keep it local.

ID-map queries use ItemQuery.withMappedName, NPCQuery.withMappedName, and TileObjectQuery.withMappedName. withName(...) means exact runtime-name filtering.

Spatial selection must state its distance reference and reachability rule. Use nearestByPath() for player-relative actions or compose walkable() with nearestToPoint(anchor) for stable work areas. Never use first() to implement a documented nearest object, NPC, player, or ground-item action.

Plugin Creation Flow

  1. Domain review: verify OSRS mechanics, account requirements, combat risk, supplies, travel, banking, and live UI assumptions.
  2. Workflow design: pick the smallest driver that fits the behavior.
  3. SDK map: cite real classes and methods for each interaction.
  4. Implementation plan: name files, state, thread boundaries, registration, tests, docs, and live verification.
  5. Implementation: write the minimum code. Register in runelite-plugin.properties only when adding a plugin.
  6. Tests: start with controller, workflow, parser, config, and state-machine tests that can run without a live client.
  7. Review: check correctness, timing, shared API usage, bootstrap gating, docs, and source consistency.
  8. Docs and SOT: update public behavior, new surfaces, registration, validation notes, and manual live gaps.

Driver Decision Matrix

ShapeUseDo not use
Plain per-tick handlerThe game state drives the next action and you re-evaluate each tick, such as dialogue, gathering, or simple banking checksLong fixed subflows where manual counters would creep in
MVC controller/runtime pluginThe plugin has many states, async data, persistent UI, or a testable runtime boundary, as Market Alcher doesSmall loops with no panel or background work
TaskPipelineA fixed-order multi-tick sequence where success advances one step, such as open bank, withdraw, equipObservation loops where the live game state should decide the next branch
AutomationStateMachineBranching, looping work with named states, recovery, and terminal success/errorLinear click chains that TaskPipeline can express
Domain workflow buildersCombat, production, banking, enchanting, or loadout work that matches an existing builderNew domain abstractions with one caller
Shared SDK helperTwo or more plugins need the same missing primitiveA plugin-specific workaround with no reuse path

Testing Flow

  • Run the narrowest meaningful Gradle suite first.
  • For public API or Javadoc changes, run .\gradlew.bat test --tests com.n3plugins.ApiJavadocCoverageTest --console plain.
  • Use JUnit 4 and Mockito 4.11. Do not use mockStatic, MockedStatic, or mockito-inline.
  • Reset ActionPacer in tests that touch pacing.
  • For WidgetApi, set the testing adapter in @Before and reset it in @After.
  • Prefer runtime interfaces and pure state tests over live-client integration tests.
  • Record live-only gaps in docs or final notes instead of pretending a unit test covers them.

See agent-testing-loop.md for the full compile, test, and live-evidence loop.

Review Flow

Review diffs in this order:

  1. User request and approved plan.
  2. Source/SOT consistency.
  3. InteractionApi.actions.*, InteractionResult, and SDK reuse.
  4. Bootstrap, pacer, walker, and client-thread ownership.
  5. Timing and anti-detection shape.
  6. Tests, docs, SOT, and manual live verification notes.

Use stop-slop on docs. Cut filler, cite real files, and avoid claims that source or live client evidence does not support.

Docs And SOT Sync

Update docs when public behavior, SDK surfaces, action contracts, plugin workflows, registration, validation, or live risks change. Update N3PLUGINS_SOURCE_OF_TRUTH.md when the canonical package map, registered plugin table, dependency list, action catalog, validation commands, or durable workflow conventions change.

Use Docusaurus-native admonitions for callouts: :::note, :::tip, :::info, :::warning[Caution], and :::danger. Do not use GitHub callout blockquotes such as > [!WARNING] in repo docs. When you touch a legacy section that uses those formats or relies on italicized Note: labels for important behavior, convert that touched section to the standard form. See documentation-style-guide.md for the full authoring standard.

Keep the SOT short. Put detailed playbooks in docs and register them in docs-site/sidebars.js so the Docusaurus site can find them.