# Skill3 — agent briefing

Java 25 CLI that **relearns a technical skill** for an AI agent: it discovers
documentation, scores it for authority and freshness against a target model's knowledge
cutoff, synthesizes an Agent Skills `SKILL.md` with an LLM, and vets both the input corpus
and the output skill with NVIDIA SkillSpector.

## The two invariants everything else serves

1. **A skill is a post-cutoff delta, not a primer.** The target model already knows the
   topic up to its cutoff; the pipeline gathers only what changed *after* it. Re-explaining
   known fundamentals wastes the whole mechanism.
2. **Discovery is topic-agnostic.** The model plans the searches. There is no per-topic
   logic anywhere, and adding some — a hardcoded query suffix, a per-skill branch — is the
   most common way to break this project without failing a test.

## Where things are

| I need… | Read |
|---|---|
| What it does, flag by flag | [`docs/USAGE.md`](docs/USAGE.md) |
| Install, keys, build | [`docs/INSTALL.md`](docs/INSTALL.md) |
| How it is structured, and why | [`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) |
| The full behavioural spec | [`docs/SPEC.md`](docs/SPEC.md) |
| Build gates, releases, guardrails | [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) |
| Generated structure diagrams | [`docs/diagrams/`](docs/diagrams/) |
| Roadmap | [`docs/PLAN.md`](docs/PLAN.md) |

## Working on it

```bash
./gradlew build          # compile + test + Error Prone, PMD, SpotBugs, ArchUnit, JaCoCo gate
./gradlew test           # tests only
./gradlew diagrams       # regenerate docs/diagrams/*.svg from the source
./gradlew run --args="learn --help"
```

The build runs on a Gradle-provisioned JDK 25 toolchain, so it does not depend on
`JAVA_HOME`. Coverage is gated at 75% instruction / 65% branch.

## Things that will bite you

- **Never hand-edit between `<!-- VIBETAGS-START -->` and `<!-- VIBETAGS-END -->`** in this
  file, `llms.txt` or `llms-full.txt`. Every compile rewrites that region from the `@AI*`
  annotations in the Java source. Text outside the markers — including everything above —
  survives. To change a guardrail, change the annotation.
- **The guardrails below are the safety tier only.** Per-element detail lives in
  [`.claude/rules/`](.claude/rules/) and loads when you open a matching source file.
- **Layering is enforced, not suggested.** An ArchUnit test asserts that `model` depends on
  nothing internal, that only `Skill3App` touches `cli`, and that the sub-packages stay
  acyclic. A convenient import in `model` fails the build.
- **Untrusted data has a defined path.** Scraped pages and `--input-file` content are
  secret-redacted and scanned *before* synthesis, fenced as DATA in the prompt, and the
  output is scanned again. Do not add a shortcut that reaches the model earlier.
- **Absence of findings is never asserted.** When SkillSpector is unavailable the scans are
  skipped and nothing is gated — "not scanned" must never be reported as "clean".

## Generated guardrails

Everything below is regenerated from source annotations on every compile.

<!-- VIBETAGS-START -->
<!-- # Generated by VibeTags | https://github.com/PIsberg/vibetags -->
<project_guardrails>
  <pii_guardrails>
    <element path="se.deversity.skill3.llm.LocalLlmClient.apiKey">
      <reason>LLM provider API key — never log, echo, or include in errors/fixtures</reason>
    </element>
    <element path="se.deversity.skill3.pipeline.BraveSearchClient.apiKey">
      <reason>Brave Search subscription token — never log, echo, or include in errors/fixtures</reason>
    </element>
  </pii_guardrails>

<rule>
  Never include runtime values of elements listed in <pii_guardrails> in logs, console output, external API calls, test fixtures, mock data, or code suggestions. Treat their values as strictly confidential.
</rule>
  <core_elements>
    <element path="se.deversity.skill3.llm.SkillMdPostProcessor">
      <sensitivity>High</sensitivity>
      <note>Deterministically guarantees SKILL.md spec compliance; model output is never trusted. Changes risk emitting invalid frontmatter — keep the parsing and frontmatter synthesis covered by SkillMdPostProcessorTest.</note>
    </element>
    <element path="se.deversity.skill3.llm.Verifier">
      <sensitivity>High</sensitivity>
      <note>Accuracy gate that re-grounds claims against the sources. Only worthwhile with a capable model — a weak model rewrites rather than grounds. Keep the prompt strict about supported-claims-only and announced-vs-shipped.</note>
    </element>
  </core_elements>

<rule>Elements listed in <core_elements> are well-tested core components. Make changes with extreme caution and verify comprehensive test coverage before proposing modifications.</rule>
  <security_elements>
    <element path="se.deversity.skill3.llm.AnthropicChatModel">
      <aspect>Anthropic API credential handling and hosted-provider network egress</aspect>
    </element>
    <element path="se.deversity.skill3.llm.LlmProviderFactory">
      <aspect>LLM provider credential resolution and model selection</aspect>
    </element>
    <element path="se.deversity.skill3.llm.LocalLlmClient">
      <aspect>outbound LLM-provider credential (Bearer token) handling</aspect>
    </element>
    <element path="se.deversity.skill3.llm.NameSanitizer">
      <aspect>output sanitization: reserved-word stripping must never be weakened</aspect>
    </element>
    <element path="se.deversity.skill3.pipeline.BraveSearchClient">
      <aspect>external-API credential handling and the only network egress with a secret token</aspect>
    </element>
    <element path="se.deversity.skill3.pipeline.DiscoveryProvider">
      <aspect>forwards the Brave subscription token to the search client; must not log it</aspect>
    </element>
    <element path="se.deversity.skill3.pipeline.HttpPageFetcher">
      <aspect>outbound page fetch egress for partly-untrusted URLs; SSRF guard must not be weakened</aspect>
    </element>
  </security_elements>

<rule>Elements listed in <security_elements> are security-critical. Never weaken their security properties. Every proposed change must be explicitly reviewed for security impact.</rule>
  <scoped_rules>
    <note>Detailed per-element guardrails for the elements below live in scoped rule files that load automatically when the matching source file is opened. Consult the referenced file before modifying an element.</note>
    <element path="se.deversity.skill3.llm.AnthropicChatModel" rules=".claude/rules/se-deversity-skill3-llm-AnthropicChatModel.md"/>
    <element path="se.deversity.skill3.llm.ChatModel" rules=".claude/rules/se-deversity-skill3-llm-ChatModel.md"/>
    <element path="se.deversity.skill3.llm.LlmProviderFactory" rules=".claude/rules/se-deversity-skill3-llm-LlmProviderFactory.md"/>
    <element path="se.deversity.skill3.llm.LocalLlmClient" rules=".claude/rules/se-deversity-skill3-llm-LocalLlmClient.md"/>
    <element path="se.deversity.skill3.llm.NameSanitizer" rules=".claude/rules/se-deversity-skill3-llm-NameSanitizer.md"/>
    <element path="se.deversity.skill3.llm.SkillMdPostProcessor" rules=".claude/rules/se-deversity-skill3-llm-SkillMdPostProcessor.md"/>
    <element path="se.deversity.skill3.llm.Verifier" rules=".claude/rules/se-deversity-skill3-llm-Verifier.md"/>
    <element path="se.deversity.skill3.model.ContextBundle" rules=".claude/rules/se-deversity-skill3-model-ContextBundle.md"/>
    <element path="se.deversity.skill3.model.RunManifest" rules=".claude/rules/se-deversity-skill3-model-RunManifest.md"/>
    <element path="se.deversity.skill3.model.Source" rules=".claude/rules/se-deversity-skill3-model-Source.md"/>
    <element path="se.deversity.skill3.pipeline.BraveSearchClient" rules=".claude/rules/se-deversity-skill3-pipeline-BraveSearchClient.md"/>
    <element path="se.deversity.skill3.pipeline.CutoffResolver" rules=".claude/rules/se-deversity-skill3-pipeline-CutoffResolver.md"/>
    <element path="se.deversity.skill3.pipeline.DiscoveryProvider" rules=".claude/rules/se-deversity-skill3-pipeline-DiscoveryProvider.md"/>
    <element path="se.deversity.skill3.pipeline.FileCorpus" rules=".claude/rules/se-deversity-skill3-pipeline-FileCorpus.md"/>
    <element path="se.deversity.skill3.pipeline.HttpPageFetcher" rules=".claude/rules/se-deversity-skill3-pipeline-HttpPageFetcher.md"/>
    <element path="se.deversity.skill3.pipeline.PageFetcher" rules=".claude/rules/se-deversity-skill3-pipeline-PageFetcher.md"/>
    <element path="se.deversity.skill3.pipeline.QueryPlanner" rules=".claude/rules/se-deversity-skill3-pipeline-QueryPlanner.md"/>
    <element path="se.deversity.skill3.pipeline.RetrievalService" rules=".claude/rules/se-deversity-skill3-pipeline-RetrievalService.md"/>
    <element path="se.deversity.skill3.pipeline.SearchClient" rules=".claude/rules/se-deversity-skill3-pipeline-SearchClient.md"/>
    <element path="se.deversity.skill3.skillspector.InputVetter" rules=".claude/rules/se-deversity-skill3-skillspector-InputVetter.md"/>
  </scoped_rules>

<rule>When you work on any element listed in <scoped_rules>, open its referenced rule file and apply the guardrails there. The rule files are the authoritative source for those elements.</rule>
</project_guardrails>
<!-- VIBETAGS-END -->
