Skip to content

Commit ed01360

Browse files
committed
docs: streamline agent guidance
1 parent bf3b185 commit ed01360

2 files changed

Lines changed: 68 additions & 515 deletions

File tree

AGENTS.md

Lines changed: 41 additions & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -1,258 +1,64 @@
1-
# Repository Guidelines
1+
# Repository Guide for Coding Agents
22

3-
## Project Structure & Modules
4-
- Root uses Gradle with multiple modules named `btrace-*`.
5-
- Core code lives in module directories (for example, `btrace-core`, `btrace-agent`, `btrace-runtime`, `btrace-client`, `btrace-instr`).
6-
- Distributions are built from `btrace-dist`.
7-
- Integration tests live in `integration-tests`; benchmarks in `benchmarks/*`; docs in `docs/`.
3+
## Start here
84

9-
## Architecture Overview
10-
- btrace-agent: Attachable Java agent that installs a class transformer and manages script lifecycle (load/unload), output routing, and optional JFR hooks.
11-
- btrace-compiler: Verifies and compiles BTrace scripts to bytecode.
12-
- btrace-instr: ASM-based instrumentation and weaving utilities used by the agent/compiler.
13-
- btrace-runtime: APIs exposed to scripts; provides safe helpers for printing, timers, and data collection.
14-
- btrace-client: CLI/attach tooling that sends compiled scripts to the target JVM and streams results.
15-
- extensions: API + implementations packaged as BTrace extensions (for example, statsd and metrics under `btrace-extensions/*`).
16-
- Flow: client attaches → compiles/sends script → agent loads and instruments target classes → runtime emits events → client displays/exports.
5+
BTrace is a Java tracing tool: the client compiles and sends a script, the agent instruments the target JVM, and the runtime emits results. The root project is a multi-module Gradle build.
176

18-
### High-Level Flow
19-
```
20-
+--------------+ attach/send +-------------+ transform +------------------+
21-
| btrace-client| -----------------> | btrace-agent| --------------> | instrumented JVM |
22-
+--------------+ +-------------+ +------------------+
23-
^ | ^ |
24-
| events/logs/stdout | | load/unload scripts |
25-
| <------------------------------------+ +-------------------------------+
26-
|
27-
+--------- optional exporters via services (eg. statsd) -------------------->
28-
```
29-
30-
### Modules (at a glance)
31-
```
32-
btrace-client -> btrace-agent -> btrace-instr
33-
| |
34-
v v
35-
btrace-runtime extensions (e.g., statsd, utils, metrics)
36-
37-
btrace-compiler (validates/compiles scripts)
38-
btrace-dist (packages binaries)
39-
```
40-
41-
## Distribution Architecture: Masked JAR
42-
43-
BTrace uses a **single masked JAR** (`btrace.jar`) as its distribution artifact. This JAR contains:
44-
45-
### Structure
46-
```
47-
btrace.jar
48-
├── META-INF/
49-
│ ├── MANIFEST.MF (Main-Class, Premain-Class, Agent-Class → io.btrace.boot.Loader)
50-
│ ├── btrace/
51-
│ │ ├── agent/*.classdata (agent classes - loaded in agent mode)
52-
│ │ ├── client/*.classdata (client classes - loaded in client mode)
53-
│ │ └── shared/*.classdata (shared classes - loaded in both modes)
54-
├── org/openjdk/btrace/boot/ (bootstrap classes - visible to JVM)
55-
└── org/openjdk/btrace/core/ (core/runtime classes from bootstrap module)
56-
```
57-
58-
### Class Loading Strategy
59-
60-
1. **Bootstrap Classes** (`.class` files in root):
61-
- Loaded by bootstrap classloader
62-
- Visible to JVM and all code
63-
- Includes: Loader, MaskedClassLoader, MaskedJarUtils
64-
- These classes initialize the masked jar system
65-
66-
2. **Agent Classes** (`.classdata` in `META-INF/btrace/agent/`):
67-
- Loaded via MaskedClassLoader in agent mode
68-
- Isolated from application classes
69-
- Includes: btrace-agent, btrace-instr, btrace-runtime, relocated jctools
70-
71-
3. **Client Classes** (`.classdata` in `META-INF/btrace/client/`):
72-
- Loaded via MaskedClassLoader in client mode
73-
- Includes: btrace-client, btrace-compiler, lanterna UI
74-
75-
4. **Shared Classes** (`.classdata` in `META-INF/btrace/shared/`):
76-
- Loaded in both agent and client modes
77-
- Includes: communication protocol, annotations, ASM core
78-
- Critical for agent-client communication
7+
- `btrace-agent` — attachable agent and script lifecycle
8+
- `btrace-compiler` — script verification and compilation
9+
- `btrace-instr` — instrumentation and weaving
10+
- `btrace-runtime` / `btrace-core` — script APIs, runtime support, and protocol
11+
- `btrace-client` — CLI and attachment client
12+
- `btrace-dist` — distribution assembly; `integration-tests` — end-to-end tests
13+
- `btrace-extensions/*` — extension API and implementations
7914

80-
### Why Masked JAR?
15+
For the developer command reference and code-navigation pointers, see [CLAUDE.md](CLAUDE.md). For user and contributor documentation, start at [docs/README.md](docs/README.md).
8116

82-
- **Single Source of Truth**: One JAR for all use cases (agent, client, standalone)
83-
- **Bootstrap Isolation**: Agent/client classes hidden from JVM, preventing conflicts
84-
- **No Embedded JARs**: Eliminates nested JAR extraction overhead
85-
- **Simplified Build**: Removed redundant uber jar - masked jar handles everything
17+
## Non-negotiable rules
8618

87-
### Build Process
19+
- Do not commit unless the changes are fully tested or the user explicitly requests a commit.
20+
- Preserve unrelated working-tree changes.
21+
- In Java code, import types and use simple names; do not introduce fully qualified type names in source.
22+
- Main code targets Java 8 and uses the Java 11 toolchain. Follow Spotless/Google Java Format.
23+
- Unit tests live in `src/test/java` and use `*Test`; integration tests live in `integration-tests/src/test/java`.
8824

89-
The masked JAR is built in `btrace-dist/build.gradle`:
90-
1. `allClassesShadow` - Creates intermediate shadow jar with all dependencies and relocations
91-
2. `prepareAgentClassdata` - Extracts agent classes, renames `.class``.classdata`
92-
3. `prepareClientClassdata` - Extracts client classes, renames `.class``.classdata`
93-
4. `prepareSharedClassdata` - Extracts shared classes, renames `.class``.classdata`
94-
5. `btraceJar` - Combines bootstrap classes (as `.class`) + masked classes (as `.classdata`)
25+
## Build and verification
9526

96-
### Debugging Tips
27+
Run Gradle with a workspace-local cache in restricted environments:
9728

98-
- **ClassNotFoundException in agent mode**: Check if class is in `META-INF/btrace/agent/` (or shared if needed)
99-
- **ClassNotFoundException in client mode**: Check if class is in `META-INF/btrace/client/` (or shared if needed)
100-
- **NoClassDefFoundError between modes**: Class may need to be in shared section
101-
- **Inspect masked JAR**: `unzip -l btrace.jar | grep -E "(\.class|\.classdata)"`
102-
- **Check manifest**: `unzip -p btrace.jar META-INF/MANIFEST.MF`
103-
104-
## Launch Modes
105-
```
106-
Launch-time (agent mode):
107-
java -javaagent:$BTRACE_HOME/libs/btrace.jar=script=MyTrace.java -jar app.jar
108-
|-> Loader.premain() -> loads agent classes from .classdata -> installs transformer
109-
110-
Attach-time (client mode):
111-
btrace <PID> MyTrace.java
112-
|-> Loader as Main-Class -> loads client classes from .classdata -> attaches to target JVM
113-
|-> Target JVM: Loader.agentmain() -> loads agent classes from .classdata -> instruments
114-
115-
Standalone (client mode):
116-
java -jar btrace.jar <args>
117-
|-> Same as attach-time, Loader delegates to client
29+
```bash
30+
GRADLE_USER_HOME=$(pwd)/.gradle-user ./gradlew :module:test
11831
```
11932

120-
## Troubleshooting
121-
- Attach disabled: if JVM was started with `-XX:+DisableAttachMechanism`, remove it or relaunch without it.
122-
- Permission errors: attach requires same OS user as target JVM; on Linux/macOS avoid sudo mixing; check container/JDK permissions.
123-
- Toolchains: ensure `JAVA_HOME` and optional `TEST_JAVA_HOME` point to valid JDKs; for integration tests, build `btrace-dist` first so client/libs exist.
33+
Do not consume Gradle output directly. Redirect it to a file, filter it to relevant lines, then read that file. Use `spotlessCheck` for validation and `spotlessApply` only when formatting changes are intended. Build `:btrace-dist:build` before integration tests.
12434

125-
### Masked JAR Troubleshooting
126-
- **ClassNotFoundException with .classdata**: MaskedClassLoader can't find class in masked sections. Check:
127-
1. Is the class in the correct section? (agent/client/shared)
128-
2. Was the class relocated? Check package name matches relocated path
129-
3. Did the build complete successfully? Rebuild with `./gradlew clean :btrace-dist:btraceJar`
130-
- **Shared classes**: If a class is used by BOTH agent and client (e.g., comm protocol, annotations), it MUST be in the shared section
131-
- **Bootstrap vs Masked**: Bootstrap classes (.class) are visible everywhere; masked classes (.classdata) are isolated per-mode
132-
- **Build order matters**: `allClassesShadow` must complete before prepare*Classdata tasks run
35+
If a restricted network environment causes address-selection failures, add:
13336

134-
## Example Script
135-
```java
136-
package helloworld;
137-
import static io.btrace.core.BTraceUtils.*;
138-
import io.btrace.core.annotations.*;
139-
import io.btrace.core.types.AnyType;
140-
141-
@BTrace
142-
public class MyTrace {
143-
@OnMethod(clazz="extra.HelloWorld", method="/.*/")
144-
public static void onAny(@ProbeMethodName String pmn) {
145-
println("entered: " + pmn);
146-
}
147-
}
37+
```bash
38+
JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false"
14839
```
149-
Run with: `btrace <PID> MyTrace.java` (see docs/BTraceTutorial.md for steps).
150-
151-
```java
152-
// Args capture
153-
package helloworld;
154-
import static io.btrace.core.BTraceUtils.*;
155-
import io.btrace.core.annotations.*;
156-
import io.btrace.core.types.AnyType;
15740

158-
@BTrace
159-
public class ArgsTrace {
160-
@OnMethod(clazz="extra.HelloWorld", method="/call.*/")
161-
public static void onCall(@ProbeMethodName String pmn, AnyType[] args) {
162-
println("args for " + pmn);
163-
printArray(args);
164-
}
165-
}
166-
```
41+
## Distribution changes
16742

168-
```java
169-
// Return value and duration
170-
package helloworld;
171-
import static io.btrace.core.BTraceUtils.*;
172-
import io.btrace.core.annotations.*;
173-
import io.btrace.core.types.AnyType;
43+
`btrace.jar` is a masked single-JAR distribution. Classes must be assigned to bootstrap, agent, client, or shared sections deliberately. Any masked-JAR structure change requires:
17444

175-
@BTrace
176-
public class ReturnTrace {
177-
@OnMethod(clazz="extra.HelloWorld", method="callC", location=@Location(Kind.RETURN))
178-
public static void onReturn(@Duration long dur, @Return AnyType ret) {
179-
println("callC ret=" + str(ret) + ", dur(ns)=" + dur);
180-
}
181-
}
45+
```bash
46+
./gradlew clean :btrace-dist:btraceJar
18247
```
18348

184-
## Build, Test, and Development
185-
! Do not consume the gradle task logs directly. !
186-
! Write the output to a file, running through grep to include only relevant information and then read the log file. !
187-
188-
- Full build: `./gradlew build` — compiles all modules and runs unit tests.
189-
- Distribution: `./gradlew :btrace-dist:build` — creates ZIP/TGZ/RPM/DEB and an exploded layout under `btrace-dist/build/resources/main`.
190-
- Unit tests: `./gradlew test` — JUnit 5, runs per-module tests.
191-
- Integration tests: first build dist, then `./gradlew -Pintegration test`.
192-
- Requires `JAVA_HOME` and typically `TEST_JAVA_HOME` (e.g., JDK 11). Example: `TEST_JAVA_HOME=$JAVA_11_HOME ./gradlew -Pintegration test`.
193-
- Formatting: `./gradlew spotlessApply` (check with `spotlessCheck`).
194-
- Coverage: `./gradlew jacocoTestReport` (CI publishes to Codecov).
195-
196-
## Coding Style & Naming
197-
- Language: Java. Source/target set to 8; toolchains compile with JDK 11.
198-
- Format: Google Java Format via Spotless. Import order enforced; unused imports removed.
199-
- Packages under `io.btrace.*`.
200-
- Module names follow `btrace-<component>` (e.g., `btrace-extensions:btrace-utils`).
201-
202-
## Testing Guidelines
203-
- Framework: JUnit Jupiter (JUnit 5).
204-
- Unit tests reside under `src/test/java`; name classes with `*Test`.
205-
- Integration tests in `integration-tests/src/test/java`; BTrace scripts under `integration-tests/src/test/btrace`.
206-
- For integration runs, ensure `btrace-dist/build/resources/main/v<version>/libs/btrace.jar` exists (created by the dist build).
207-
- The masked JAR is used for all integration tests - both agent and client modes use the same artifact.
208-
209-
## Commit & Pull Request Guidelines
210-
- Commit style: Conventional Commits (e.g., `feat(core): add probe`, `fix(instr): handle null arg`).
211-
- PRs must be from signers of the Oracle Contributor Agreement (OCA) — see README.
212-
- PR checklist:
213-
- Clear description and rationale; link related issues.
214-
- Tests updated/added; CI green across unit and integration suites.
215-
- Formatting passes (`spotlessCheck`); no unrelated changes.
216-
- For behavior changes, include before/after notes or relevant logs.
217-
218-
## Tips & Environment
219-
- Useful env vars: `JAVA_HOME`, `TEST_JAVA_HOME`, `BTRACE_TEST_DEBUG=true` (verbose integration tests), optional `BTRACE_HOME` when using the exploded dist.
220-
- Example exploded dist path: `btrace-dist/build/resources/main/v2.2.6/`.
221-
222-
### Restricted/CI Environments
223-
- Prefer a workspace-local Gradle cache to avoid permission issues: set `GRADLE_USER_HOME=$(pwd)/.gradle-user`.
224-
- If network interfaces are restricted, force IPv4 to avoid wildcard IP detection errors: set `JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false"`.
225-
- Example: `GRADLE_USER_HOME=$(pwd)/.gradle-user JAVA_TOOL_OPTIONS="-Djava.net.preferIPv4Stack=true -Djava.net.preferIPv6Addresses=false" ./gradlew :btrace-dist:buildZip -x test`
226-
227-
## Common Patterns & Lessons Learned
228-
229-
### Adding New Classes
230-
1. **Determine the section**: Is the class used by agent, client, or both?
231-
- Agent only → prepareAgentClassdata include pattern
232-
- Client only → prepareClientClassdata include pattern
233-
- Both → prepareSharedClassdata include pattern
234-
2. **Update build.gradle**: Add include pattern in the appropriate task
235-
3. **Rebuild and test**: `./gradlew clean :btrace-dist:btraceJar && ./gradlew -Pintegration test`
49+
Read [Masked JAR Architecture](docs/architecture/MaskedJarArchitecture.md) before modifying its class layout or loader behavior.
23650

237-
### Dependency Relocation
238-
- All third-party dependencies are relocated to `io.btrace.libs.*`
239-
- Relocations happen in `allClassesShadow` task using Shadow plugin
240-
- Common relocations: ASM, SLF4J, JCTools
241-
- After relocation, classes are extracted and masked in prepare*Classdata tasks
51+
## Documentation placement
24252

243-
### Build Simplification Wins
244-
- **Before**: Separate agent.jar, client.jar, boot.jar, uber.jar (4 artifacts)
245-
- **After**: Single btrace.jar with masked sections (1 artifact)
246-
- **Result**: Simpler build, smaller distribution, easier maintenance
53+
- User-facing and contributor documentation belongs in `docs/`; keep [docs/README.md](docs/README.md) current when adding a guide.
54+
- Plans and session notes belong in `internal/plans/` (or `internal/superpowers/plans/`).
55+
- Design/requirement specs belong in `internal/specs/` (or `internal/superpowers/specs/`); libretto/muse files belong in `internal/libretti/`.
56+
- Never create or write to a singular `doc/` directory, or add plans, agent notes, or internal material below `docs/`.
24757

248-
### ClassLoader Isolation
249-
- Bootstrap classes can see everything (including masked sections via MaskedClassLoader)
250-
- Application classes cannot see masked sections (isolation prevents conflicts)
251-
- Masked classes in agent mode cannot see masked classes in client mode (intentional isolation)
252-
- Shared section solves cross-mode visibility when needed (e.g., command serialization)
58+
## Reference map
25359

254-
## Hard rules
255-
- Never commit changes unless they are fully tested or you are explicitly asked to commit
256-
- Do not use FQNs directly! Always import types and use simple type names in the code!
257-
- When adding classes to masked jar, always consider: agent-only, client-only, or shared?
258-
- Rebuild the distribution after any changes to masked jar structure: `./gradlew clean :btrace-dist:btraceJar`
60+
- [Contribution workflow](CONTRIBUTING.md)
61+
- [Instrumentation analysis](docs/architecture/BTraceInstrAnalysis.md) and [backend selection](docs/architecture/InstrumentationBackends.md)
62+
- [v2 wire protocol](docs/architecture/Version2ProtocolArchitecture.md)
63+
- [Extension development](docs/BTraceExtensionDevelopmentGuide.md) and [interface rules](docs/ExtensionInterfaceRules.md)
64+
- [Troubleshooting](docs/Troubleshooting.md)

0 commit comments

Comments
 (0)