Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 5 additions & 5 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,12 +124,12 @@ The plugin operates in two logical phases:

**Phase 1 — File Indexing & Summarization**
```
[Source .java files] → SourceFileIndexer → [*.java.ai.md files (with s/k filled)]
[Source .java files] → SourceFileIndexer → [*.java.ai.md files (deterministic header + AI body)]
```

**Phase 2 — Package Aggregation & Summarization**
```
[*.java.ai.md files] → PackageIndexer → [package.ai.md files (with s/k filled)]
[*.java.ai.md files] → PackageIndexer → [package.ai.md files (deterministic header + AI body)]
```

### Key Components
Expand Down Expand Up @@ -203,8 +203,8 @@ the header machine-parseable without AI involvement (see

| Goal | Description |
|---|---|
| `ai-index:generate` | Phase 1: index source files and fill AI summary/keywords fields |
| `ai-index:aggregate-packages` | Phase 2: aggregate package index files and fill AI summary/keywords fields |
| `ai-index:generate` | Phase 1: index source files and fill the AI-generated document body |
| `ai-index:aggregate-packages` | Phase 2: aggregate package index files and fill the AI-generated document body |

### Key Parameters (`GenerateMojo`)

Expand Down Expand Up @@ -326,7 +326,7 @@ See [`../workspace/workflows/pull-request-workflow.md`](../workspace/workflows/p
## Key Design Principles

1. **Local-first** — all AI inference runs locally via llama.cpp; no cloud API calls, no data leaves the machine.
2. **Deterministic indexing** — same source produces the same `.ai.md` skeleton; only AI-generated fields (`s`, `k`) vary.
2. **Deterministic indexing** — same source produces the same `.ai.md` skeleton (deterministic header); only the AI-generated body varies.
3. **Incremental updates** — files with existing summaries are skipped unless `force=true`; checksums detect source changes.
4. **Unified indexing and summarization** — each indexer (`SourceFileIndexer`, `PackageIndexer`) both creates the `.ai.md` skeleton and fills in AI fields in a single pass; no separate summarization step is needed.
5. **Provider abstraction** — AI backends are pluggable through `AiGenerationProvider`; mock provider enables fully deterministic tests.
Expand Down
146 changes: 121 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ A Maven plugin for generating hierarchical, AI-readable documentation of source
It creates structured `.ai.md` files per source file and aggregates them into package-level summaries for fast semantic navigation and retrieval.
## Features
- Generate AI summaries for Java source files
- Extract keyword metadata for search and indexing
- Weave searchable type, API and domain names into every summary
- Aggregate summaries at package level
- Uses local models via llama.cpp (no cloud dependency)
- Incremental updates (skips unchanged files)
Expand All @@ -100,10 +100,20 @@ The plugin runs in two phases.
- D: 2026-03-15T23:31:52Z
- T: 2026-03-19T18:13:31Z
- G: 1.0.0
- A: 0.0.0
- X: file
- K: AiMdDocument, AiMdHeader, record, metadata, markdown
#### AiMdDocument.java
Represents a document consisting of a structured metadata header and a markdown body. Ensures non-null invariants and encapsulates AI-generated content.
---
> Immutable value type pairing a deterministic metadata header with the AI-generated markdown body of one .ai.md document.

#### Purpose
- Hold one parsed `.ai.md` document as an `AiMdHeader` plus its markdown body.

#### Type
- record-shaped value class (Java); marked `@ConvertToRecord`.

#### Public API
- `header() -> AiMdHeader` — the document's metadata header.
- `body() -> String` — the AI-generated markdown body.
```
## Requirements
- Java 8+ (production code targets Java 8; CI builds on Java 8 via temurin)
Expand All @@ -123,12 +133,95 @@ It is published on Maven Central and resolves automatically — no manual instal
</dependency>
```
## Configuration
Minimal setup in POM:
```
<properties>
<ai.index.model.path>/path/to/model.gguf</ai.index.model.path>
<ai.index.output.directory>${project.basedir}/src/site/ai</ai.index.output.directory>
</properties>
The plugin is configured from three building blocks, declared on the plugin inside
`<build><plugins>`:

1. **`<aiDefinitions>`** — define each GGUF model once (path + sampling parameters), each with a `<key>`.
2. **`<promptDefinitions>`** — define each prompt template once, each with a `<key>`. A template takes
two `%s` placeholders: the file/package name and the source (or, for packages, the child summaries).
3. **`<fieldGenerations>`** — per goal, map one `<promptKey>` to one `<aiDefinitionKey>`. This is
**required**: a goal with no field generation fails fast.

```xml
<plugin>
<groupId>net.ladenthin</groupId>
<artifactId>llamacpp-ai-index-maven-plugin</artifactId>
<version>1.0.0</version>

<configuration>
<!-- outputDirectory defaults to ${project.basedir}/src/site/ai -->
<subtrees>
<subtree>src/main/java/com/example</subtree>
</subtrees>
<!-- provider defaults to "mock"; use "llamacpp-jni" to run a real GGUF model -->
<generationProvider>llamacpp-jni</generationProvider>

<!-- 1) Models: define once, reference by key. -->
<aiDefinitions>
<aiDefinition>
<key>coder</key>
<modelPath>/path/to/model.gguf</modelPath>
<contextSize>32768</contextSize>
<maxOutputTokens>1536</maxOutputTokens>
<temperature>0.7</temperature>
<threads>8</threads>
</aiDefinition>
</aiDefinitions>

<!-- 2) Prompts (abbreviated). See the ai-index-selftest profile in this repo's
pom.xml for the full, tested file-body / package-body templates. -->
<promptDefinitions>
<promptDefinition>
<key>file-body</key>
<template><![CDATA[Summarize ONE source file as structured markdown.

File: %s

Source:
%s]]></template>
</promptDefinition>
<promptDefinition>
<key>package-body</key>
<template><![CDATA[Summarize ONE package from its already-generated file summaries.

Package: %s

File summaries:
%s]]></template>
</promptDefinition>
</promptDefinitions>
</configuration>

<!-- 3) Bind each goal to a phase and map prompt -> model per goal. -->
<executions>
<execution>
<id>ai-generate</id>
<phase>generate-resources</phase>
<goals><goal>generate</goal></goals>
<configuration>
<fieldGenerations>
<fieldGeneration>
<promptKey>file-body</promptKey>
<aiDefinitionKey>coder</aiDefinitionKey>
</fieldGeneration>
</fieldGenerations>
</configuration>
</execution>
<execution>
<id>ai-aggregate-packages</id>
<phase>process-resources</phase>
<goals><goal>aggregate-packages</goal></goals>
<configuration>
<fieldGenerations>
<fieldGeneration>
<promptKey>package-body</promptKey>
<aiDefinitionKey>coder</aiDefinitionKey>
</fieldGeneration>
</fieldGenerations>
</configuration>
</execution>
</executions>
</plugin>
```
## Usage
Run AI index generation:
Expand All @@ -140,22 +233,25 @@ With native llama tests:
mvn clean install -Pai-index-selftest -DrunNativeLlamaTests=true
```
## Plugin Configuration
Key parameters:
- outputDirectory: target directory for `.ai.md` files
- subtrees: source directories to index
- generationProvider: AI backend (`llamacpp-jni`)
- llamaModelPath: path to GGUF model
- llamaContextSize: context window
- llamaMaxTokens: output token limit
- llamaTemperature: sampling temperature
- llamaThreads: CPU threads
Run-level parameters (set in `<configuration>`):
- `outputDirectory` — target directory for `.ai.md` files (default: `${project.basedir}/src/site/ai`)
- `subtrees` — source directories to index, relative to the project base dir (default: `src/main/java`)
- `fileExtensions` — file extensions to index (default: `.java`)
- `generationProvider` — AI backend: `mock` (default) or `llamacpp-jni`
- `force` — regenerate even when a body already exists (default: `false`)
- `skip` — skip the goal entirely (default: `false`)
- `aiDefinitions` / `promptDefinitions` — named models / prompt templates, referenced by key
- `fieldGenerations` — per goal: which `promptKey` runs with which `aiDefinitionKey` (**required**)

Per-model parameters — model path, context size, output tokens, temperature, top-p / top-k,
repeat penalty, threads — live inside each `<aiDefinition>`, not as top-level parameters.
## Prompt System
The plugin uses configurable prompts:
- file-summary
- file-keywords
- package-summary
- package-keywords
Prompts are optimized to avoid code blocks, formatter artifacts, empty outputs, and produce structured markdown.
Prompts are defined in the plugin configuration (`<promptDefinitions>`) and referenced by key
from `<fieldGenerations>`. The self-test profile defines two:
- `file-body` — summarizes a single source file
- `package-body` — synthesizes a package summary from the already-generated file summaries
Each summary begins with a one-sentence blockquote lead, followed by structured `####` sections.
Prompts are optimized to avoid code blocks, formatter artifacts, and empty outputs, and to produce structured markdown.
## Output Structure
```
src/site/ai/
Expand Down
Loading