Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9c96e8f
Add performance-engineer-in-a-box ideation document
claude Sep 7, 2026
0b47195
Add jafar-perf plugin and the MCP groundwork it needs
claude Sep 7, 2026
872b183
Add design doc for an LLM inside the Jafar shells
claude Sep 7, 2026
dd50054
Add 'ask' - an LLM inside the shell, with seams for the agentic mode
claude Sep 7, 2026
a1e0a60
Wire ask into the unified jafar-shell, so it reaches every format
claude Sep 7, 2026
aa65cc6
Make the shell's LLM multi-provider, and fix ask where it was broken
claude Sep 8, 2026
7e99725
Make an MCP transport-test failure say what actually went wrong
claude Sep 8, 2026
025012c
Put the plugin install instructions where people will find them
claude Sep 8, 2026
70e6e5a
Publish jafar-perf from its own repository, not this one
claude Sep 8, 2026
07bd4ba
Point the plugin links at the repository that actually exists
claude Sep 8, 2026
9b5469a
Point the plugin links at btraceio/jafar-perf-box
claude Sep 13, 2026
88aa3ff
Point the remaining repository links at btraceio/jafar
claude Sep 13, 2026
54ad12c
Report the real version in the MCP handshake
claude Sep 13, 2026
87facfa
Give ask, explain and llm the completion and help they shipped without
claude Sep 13, 2026
cbb0270
Keep the API key in a file instead of an environment variable
claude Sep 13, 2026
d25dfa4
Make dry-run a flag on the verb it belongs to
claude Sep 13, 2026
2badd33
Make llm.api-key work for the Anthropic backend too
claude Sep 13, 2026
dbf7a85
Make `set llm.<name> = <value>` actually work
claude Sep 13, 2026
ee09f52
Turn AGENTS.md into an entry point, and write down what this session …
claude Sep 13, 2026
acf9b38
Repoint the two AGENTS.md line references at their new sections
claude Sep 13, 2026
d31df8a
Discover reasoning models from the reply, not from a name list
claude Sep 13, 2026
7de3f51
Tell the model what each event type is for
claude Sep 13, 2026
f162bcb
Let the model ask what fields a type has
claude Sep 13, 2026
068e6c1
Stop offering event types that hold no events
claude Sep 13, 2026
395ce06
Add `analyze`: an investigation loop, not a translation
claude Sep 13, 2026
b1c2dc5
Fix two ways analyze wastes a step
claude Sep 13, 2026
eb2edf9
Start the analysis extraction, and build the net it needs first
claude Sep 13, 2026
35ee6cf
Move use, tsa and diagnose out of the MCP server
claude Sep 13, 2026
92cad81
Let analyze call diagnose, use and tsa
claude Sep 13, 2026
efc45f5
Distil this session's lessons, and make the knowledge base maintain i…
claude Sep 13, 2026
a933df1
Make groupBy say when its key matched nothing, and read 'value' as th…
claude Sep 13, 2026
d42878a
Make analyze a superset of ask: show the rows, feed explain, honour l…
claude Sep 13, 2026
a8a386d
Rename the LLM commands: 'ask' investigates, 'as-query' translates, '…
claude Sep 13, 2026
65a9d46
Drop a settings count that the settings outgrew
claude Sep 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/config.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
blank_issues_enabled: false
contact_links:
- name: GitHub Discussions
url: https://github.com/jbachorik/jafar/discussions
url: https://github.com/btraceio/jafar/discussions
about: For general discussions, questions, and community support
- name: Security Issue
url: https://github.com/jbachorik/jafar/blob/main/SECURITY.md
url: https://github.com/btraceio/jafar/blob/main/SECURITY.md
about: Report security vulnerabilities privately (DO NOT create public issues)
4 changes: 2 additions & 2 deletions .github/ISSUE_TEMPLATE/question.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ body:
Have a question about using JAFAR? We're here to help!

**Before asking:**
- Check the [README.md](https://github.com/jbachorik/jafar/blob/main/README.md) for basic usage
- Review [LIMITATIONS.md](https://github.com/jbachorik/jafar/blob/main/LIMITATIONS.md) for known limitations
- Check the [README.md](https://github.com/btraceio/jafar/blob/main/README.md) for basic usage
- Review [LIMITATIONS.md](https://github.com/btraceio/jafar/blob/main/LIMITATIONS.md) for known limitations
- Search existing issues and discussions

- type: dropdown
Expand Down
461 changes: 82 additions & 379 deletions AGENTS.md

Large diffs are not rendered by default.

222 changes: 219 additions & 3 deletions CHANGELOG.md

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ We are committed to providing a welcoming and inclusive environment for all cont

### Finding Work

- Check issues labeled [`good first issue`](https://github.com/jbachorik/jafar/labels/good%20first%20issue) for beginner-friendly tasks
- Look for [`help wanted`](https://github.com/jbachorik/jafar/labels/help%20wanted) issues
- Check issues labeled [`good first issue`](https://github.com/btraceio/jafar/labels/good%20first%20issue) for beginner-friendly tasks
- Look for [`help wanted`](https://github.com/btraceio/jafar/labels/help%20wanted) issues
- Review the [LIMITATIONS.md](LIMITATIONS.md) for areas needing improvement

## Coding Standards
Expand Down
2 changes: 1 addition & 1 deletion LIMITATIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ exec.submit(() -> p.run()); // ❌ Don't share parser across threads
## Reporting Issues

If you encounter limitations not documented here, please report them at:
https://github.com/jbachorik/jafar/issues
https://github.com/btraceio/jafar/issues

When reporting, please include:
- JAFAR version
Expand Down
2 changes: 1 addition & 1 deletion PERFORMANCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ Results are saved to: `benchmarks/build/results/jmh/results.json`

```bash
# Clone repository
git clone https://github.com/jbachorik/jafar.git
git clone https://github.com/btraceio/jafar.git
cd jafar

# Fetch test resources
Expand Down
78 changes: 78 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -508,10 +508,88 @@ jfr> events/jdk.ExecutionSample | decorateByTime(jdk.JavaMonitorWait, fields=mon

See **[Event Decoration and Joining](doc/cli/Tutorial.md#event-decoration-and-joining)** for advanced correlation and joining capabilities.

## Ask Your Recording a Question

`ask` — or `?` for short — investigates: it runs a query, reads the result, decides what to look at
next, and concludes.

```
jfr> ? why is this workload slow
> events/jdk.ExecutionSample | groupBy(sampledThread/javaName) | top(3, by=count)
3 rows
| count | key |
+-------+----------+
| 8412 | main |
| 210 | worker-1 |

The samples concentrate on one thread, so the next step is that thread's call sites
rather than more parallelism.

Transcript: ~/.jafar/investigations/ask-20260913-202249.jfrs
```

`as-query` is the one-shot form — one question, one query, shown and run:

```
jfr> as-query which threads used the most CPU?

# Groups execution samples by thread name and ranks the ten busiest.

events/jdk.ExecutionSample | groupBy(sampledThread/javaName) | top(10, by=count)
```

Every query is printed either way — so a wrong guess is visible, and you learn JfrPath as you go —
and an investigation writes the queries it ran to a re-runnable `.jfrs` script, so its conclusion
can be checked rather than trusted. The recording itself never leaves your machine: the model
composes the queries, the shell runs them.

Three ways to authenticate, in the order most people want them:

```bash
# 1. A key in a file only you can read — no environment variable, no CLI to install
mkdir -p ~/.config/jafar
printf 'llm.api-key = sk-ant-...\n' > ~/.config/jafar/llm.properties
chmod 600 ~/.config/jafar/llm.properties

# 2. Or the provider's environment variable
export ANTHROPIC_API_KEY=sk-ant-...

# 3. Or keylessly, if you have the Anthropic CLI (optional — note the plural 'anthropics')
brew install anthropics/tap/ant && ant auth login
```

Or none of the above: `set llm.backend = ollama` runs a local model, and nothing leaves the machine.

`ask --dry-run <question>` prints exactly what would be sent without sending it, and result data is
redacted by default. See **[LLM setup](doc/cli/LlmSetup.md)**,
**[the tutorial](doc/cli/AskTutorial.md)** and **[what leaves your machine](doc/cli/LlmPrivacy.md)**.

## Claude Code Plugin

`jafar-perf` adds the methodology the tools do not carry: nine skills (`triage`, `cpu`, `latency`,
`gc`, `memory-leak`, `heap-diff`, `compare`, `jfrpath`, `report`) and seven agents that know *which*
analysis to run on an unfamiliar recording or heap dump, not just how to run one.

```
/plugin marketplace add btraceio/jafar-perf-box
/plugin install jafar-perf@btraceio
```

The plugin bundles `.mcp.json`, so installing it **also registers the `jafar` MCP server** described
below — no separate `claude mcp add` is needed. [JBang](https://www.jbang.dev) must be on your PATH;
it fetches the server on first use.

It lives in **[btraceio/jafar-perf-box](https://github.com/btraceio/jafar-perf-box)**, not in this
repository: adding a marketplace clones its repository, and there is no reason to pull Jafar's
binary test recordings onto a machine that only wants the skills.

## MCP Server

JAFAR includes an MCP (Model Context Protocol) server that enables AI agents like Claude to analyze JFR recordings. See **[jfr-mcp/README.md](jfr-mcp/README.md)** for details.

Installing the plugin above already registers it; the rest of this section is for using the server
on its own, or from a client other than Claude Code.

### Quick Install

```bash
Expand Down
6 changes: 3 additions & 3 deletions RELEASE_NOTES_v0.1.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,15 +103,15 @@ See [LIMITATIONS.md](LIMITATIONS.md) for complete list and workarounds.

## Documentation

- **README**: https://github.com/jbachorik/jafar#readme
- **README**: https://github.com/btraceio/jafar#readme
- **Examples**: `examples/` directory in the repository
- **Javadoc**: Comprehensive API documentation on all public classes

## Contributing

We welcome contributions! Please read [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.

To report bugs or request features, use our [GitHub issue templates](https://github.com/jbachorik/jafar/issues/new/choose).
To report bugs or request features, use our [GitHub issue templates](https://github.com/btraceio/jafar/issues/new/choose).

For security vulnerabilities, see [SECURITY.md](SECURITY.md) (do not create public issues).

Expand All @@ -136,4 +136,4 @@ Built with:

---

**Full Changelog**: https://github.com/jbachorik/jafar/blob/v0.1.0/CHANGELOG.md
**Full Changelog**: https://github.com/btraceio/jafar/blob/v0.1.0/CHANGELOG.md
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ We will credit reporters in release notes (unless they prefer to remain anonymou
## Security Updates

Security updates will be announced via:
- GitHub Security Advisories: https://github.com/jbachorik/jafar/security/advisories
- GitHub Security Advisories: https://github.com/btraceio/jafar/security/advisories
- Release notes in CHANGELOG.md
- Git tags with security fix annotations

Expand Down
4 changes: 2 additions & 2 deletions demo/doc/DEMO_README.md
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,8 @@ See parent project license.

## Links

- **Project:** https://github.com/jbachorik/jafar
- **Issues:** https://github.com/jbachorik/jafar/issues
- **Project:** https://github.com/btraceio/jafar
- **Issues:** https://github.com/btraceio/jafar/issues
- **JFR Documentation:** https://docs.oracle.com/en/java/javase/21/jfapi/

---
Expand Down
32 changes: 30 additions & 2 deletions doc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ This directory contains comprehensive documentation for the Jafar project, organ

```
doc/
├── agents/ # Contributor & AI-assistant guidance (entry point: ../AGENTS.md)
├── parser/ # Parser API Documentation
├── cli/ # JFR Shell (CLI) Documentation
├── mcp/ # MCP Server Documentation
Expand All @@ -16,14 +17,37 @@ doc/

---

## 🤖 Working on Jafar (`agents/`)

Guidance for contributors and AI coding assistants. The entry point is
[AGENTS.md](../AGENTS.md) in the repository root; these are the areas it links to.

| Document | Description |
|----------|-------------|
| [Verification.md](agents/Verification.md) | **How to know a change works here** — the rules, and the case files behind each |
| [DataShapes.md](agents/DataShapes.md) | Structures that lie — the wrong-shape bug class that keeps recurring |
| [Build.md](agents/Build.md) | Prerequisites, build and test commands, the Go parser's toolchain |
| [Architecture.md](agents/Architecture.md) | Parser APIs, coding style, testing strategy, composite build |
| [Shells.md](agents/Shells.md) | The shells, JfrPath, tab completion, backend plugins |
| [Mcp.md](agents/Mcp.md) | MCP server tools, prompts, resources, findings contract |
| [Llm.md](agents/Llm.md) | The `ask` and `as-query` commands, the LLM SPI, and why they are shaped that way |
| [Release.md](agents/Release.md) | Release process (see also [RELEASING.md](../RELEASING.md)) |

**Start here if you want to:**
- Make a change and have it actually work — read `Verification.md` first
- Understand why a module is split the way it is
- Add a shell module, a backend plugin, or an MCP tool

---

## 📚 Parser API (`parser/`)

Documentation for Jafar's typed and untyped parsing APIs.

| Document | Description |
|----------|-------------|
| [TypedAPITutorial.md](parser/TypedAPITutorial.md) | Tutorial for strongly-typed JFR parsing with annotated interfaces |
| [unTypedAPITutorial.md](parser/unTypedAPITutorial.md) | Tutorial for flexible map-based JFR parsing |
| [UntypedAPITutorial.md](parser/UntypedAPITutorial.md) | Tutorial for flexible map-based JFR parsing |
| [MapVariables.md](parser/MapVariables.md) | Guide to using map data structures in scripts |

**Start here if you want to:**
Expand All @@ -48,6 +72,9 @@ Documentation for the interactive shell command-line interface (JFR, pprof, heap
| [BackendQuickstart.md](cli/BackendQuickstart.md) | Build a custom backend in 10 minutes |
| [CommandRecording.md](cli/CommandRecording.md) | Recording and replaying command workflows |
| [ScriptExecution.md](cli/ScriptExecution.md) | Executing scripts for batch analysis |
| [LlmSetup.md](cli/LlmSetup.md) | Setting up `ask` and `as-query`: API key and keyless auth, settings, cost |
| [AskTutorial.md](cli/AskTutorial.md) | Asking a recording questions in plain language (and learning JfrPath by doing it) |
| [LlmPrivacy.md](cli/LlmPrivacy.md) | Exactly what leaves your machine, redaction, and untrusted recordings |
| [pprof-shell-tutorial.md](cli/pprof-shell-tutorial.md) | Tutorial for pprof profile analysis |
| [hdump-shell-tutorial.md](cli/hdump-shell-tutorial.md) | Tutorial for heap dump analysis |

Expand All @@ -70,6 +97,7 @@ Documentation for the Model Context Protocol server for AI-assisted JFR analysis
| [Tutorial.md](mcp/Tutorial.md) | Complete MCP server setup and usage guide |
| [JBANGUsage.md](mcp/JBANGUsage.md) | JBang distribution guide for MCP server |
| [JBANGCatalogSetup.md](mcp/JBANGCatalogSetup.md) | Setting up external JBang catalog repository |
| [WhenToUseWhich.md](mcp/WhenToUseWhich.md) | In-shell `ask` vs the MCP server vs the `jafar-perf` plugin |

**Start here if you want to:**
- Use Claude Desktop to analyze JFR files
Expand Down Expand Up @@ -123,7 +151,7 @@ Work-in-progress documentation and implementation notes.
### I want to...

**Parse JFR files programmatically:**
→ Start with [parser/TypedAPITutorial.md](parser/TypedAPITutorial.md) or [parser/unTypedAPITutorial.md](parser/unTypedAPITutorial.md)
→ Start with [parser/TypedAPITutorial.md](parser/TypedAPITutorial.md) or [parser/UntypedAPITutorial.md](parser/UntypedAPITutorial.md)

**Analyze JFR files interactively:**
→ Start with [cli/Tutorial.md](cli/Tutorial.md)
Expand Down
85 changes: 85 additions & 0 deletions doc/agents/Architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# Architecture and conventions

The parser APIs, coding style, testing strategy, and the composite build.
The module map is in [AGENTS.md](../../AGENTS.md#module-map).

## Coding Style & Naming Conventions
- Language: Java 25 (shell/MCP modules), Java 8 bytecode (parser/tools/demo), Groovy (plugin). Indent 4 spaces, no tabs; aim for 120 col width.
- Packages: `io.jafar.*`. Classes `PascalCase`, methods/fields `camelCase`, constants `UPPER_SNAKE_CASE`.
- Keep public API minimal; prefer package-private for internals. Use meaningful names and final where sensible.

## Pre-commit Formatting
- Spotless enforces formatting for Java, Groovy, and Gradle files.
- Git hook: `.githooks/pre-commit` runs `./gradlew spotlessApply` and restages changes.
- If hooks don't run, set `git config core.hooksPath .githooks` once.

## Parser APIs
- **Typed API**: Uses interface definitions with `@JfrType("event.name")` annotations
- **Untyped API**: Returns events as `Map<String, Object>` with wrapper types for arrays/complex values
- Both APIs support handler registration and synchronous event processing

## Key Classes to Understand
- `JafarParser`: Factory methods for creating typed/untyped parsers
- `TypedJafarParserImpl`/`UntypedJafarParserImpl`: Core implementation classes
- `ParsingContext`: Manages shared resources and metadata across parsing sessions
- `ChunkParserListener`: Low-level parsing lifecycle hooks
- `Values`: Utility class for extracting values from untyped event maps

## Testing Strategy
- Frameworks: JUnit Jupiter 5, Mockito. Place tests under `src/test/java` mirroring package paths.
- Name tests `*Test.java`; parameterized tests encouraged for edge cases; see existing fuzz/stability tests in `parser-core` and `parser-codegen`.
- JFR test files stored in `src/test/resources/`
- Tests use JUnit 5 with large heap allocation (8GB max, 1GB min)
- Mock recordings created using JMC FlightRecorder writer

## Gradle Plugin
The `generateJafarTypes` task generates typed interfaces from JFR metadata:
- Can use runtime JVM metadata or existing JFR files as input
- Supports filtering by event type names
- Configurable output package and directory

## Composite Build Configuration

The project uses Gradle composite builds to ensure the demo project and other consumers always use the latest local source code during development.

**Why this is needed:**
- The `jafar-gradle-plugin` depends on `jafar-parser`
- Without composite builds, the plugin would resolve `jafar-parser` from Maven repositories (which may be stale)
- Composite builds ensure the plugin uses the current local parser source code

**Root project (`settings.gradle`):**
```gradle
// Let builds resolve the in-repo Gradle plugin by ID without publishing
pluginManagement {
includeBuild('jafar-gradle-plugin')
}

// Wire the plugin build to use the in-repo parser project instead of a published module
includeBuild('jafar-gradle-plugin') {
dependencySubstitution {
substitute(module("io.btrace:jafar-parser")).using(project(":parser"))
substitute(module("io.btrace:jafar-parser-core")).using(project(":parser-core"))
}
}
```

**Demo project (`demo/settings.gradle`):**
```gradle
// Include the plugin for use
pluginManagement {
includeBuild('../jafar-gradle-plugin')
}

// Include parent build to get access to parser module
includeBuild('..') {
dependencySubstitution {
substitute(module("io.btrace:jafar-parser")).using(project(":parser"))
substitute(module("io.btrace:jafar-parser-core")).using(project(":parser-core"))
}
}
```

**Important notes:**
- When modifying parser code, the changes are immediately available to the plugin (no `publishToMavenLocal` needed)
- If you encounter `StackOverflowError` in `TypeGenerator`, ensure both `/parser-core/src/main/java/io/jafar/utils/TypeGenerator.java` and `/parser-core/src/java21/java/io/jafar/utils/TypeGenerator.java` are updated
- After changing settings.gradle, run `./gradlew --stop` and `rm -rf demo/.gradle/` to clear caches
Loading
Loading