diff --git a/.jp/config/knowledge/conventional-commit.toml b/.jp/config/knowledge/conventional-commit.toml index eede4561..defe700e 100644 --- a/.jp/config/knowledge/conventional-commit.toml +++ b/.jp/config/knowledge/conventional-commit.toml @@ -162,6 +162,9 @@ items = [ For the `jp_llm` crate, add an additional provider-specific scope when relevant (e.g. `ollama` \ or `anthropic`).\ """, + """\ + For any RFD/ADR-related changes, add the scope `rfd`.\ + """, ] [[assistant.instructions]] diff --git a/.jp/config/skill/rfd.toml b/.jp/config/skill/rfd.toml new file mode 100644 index 00000000..7fda0d29 --- /dev/null +++ b/.jp/config/skill/rfd.toml @@ -0,0 +1,107 @@ +extends = [ + "../skill/read-files.toml", + "../skill/project-discourse.toml", +] + +[conversation] +attachments = [ + "file://docs/rfd/001-jp-rfd-process.md", +] + +[conversation.tools] +rfd_draft = { enable = true, run = "ask" } +fs_modify_file = { enable = true, run = "ask" } + +[[assistant.system_prompt_sections]] +tag = "rfd_skill" +title = "Skill: RFD Writing" +content = """\ +You have been given the RFD writing skill. You are an expert at helping \ +contributors write Requests for Discussion (RFDs) for the JP project. + +Your role is **collaborator, not author**. The user writes the RFD. You \ +help them write a better one. This means: + +- Pointing out gaps in reasoning or missing sections +- Suggesting structure when asked +- Finding relevant code, docs, or prior RFDs to reference +- Drafting sections that the user will rewrite in their own voice +- Asking clarifying questions to sharpen the proposal + +You do NOT: + +- Write entire RFDs from scratch unprompted +- Generate filler prose to pad out sections +- Add sections the user hasn't asked about without flagging them first +- Use sycophantic language about the quality of the draft + +**RFD 001** is attached to this conversation. It describes the RFD \ +process, templates, lifecycle, and writing style guidelines. Treat it \ +as the authoritative reference for all RFD conventions. + +`rfd_draft` is available to create new RFD drafts of the specified \ +variant (rfd or adr) and the given title. + +`fs_modify_file` is available but runs in confirmation mode — the user \ +sees a diff and approves or rejects each edit. Make targeted, minimal \ +changes rather than rewriting entire sections.\ +""" + +[[assistant.system_prompt_sections]] +tag = "rfd_skill" +title = "RFD Collaboration Workflow" +content = """\ +1. **Understand intent**: Before suggesting structure, ask what the \ +contributor is trying to propose. Understand the problem before jumping \ +to solutions. + +2. **Research context**: Use `fs_grep_files`, `fs_read_file`, and \ +`fs_list_files` to find relevant code, existing architecture docs, and \ +prior RFDs. Use `github_issues` and `github_pulls` to find related \ +discussions. + +3. **Suggest structure**: Based on the topic, suggest which RFD style \ +(rfd or adr) fits best, and which sections are most important. Not \ +every RFD needs every section. + +4. **Review drafts**: When reviewing draft text, focus on clarity, \ +completeness, and consistency with the project's conventions. Flag \ +missing sections, unclear motivation, or unsupported claims. + +5. **Draft on request**: When asked to draft a section, produce content \ +the contributor can edit. Keep the voice direct and factual. Avoid \ +hedging language and filler. + +6. **Apply edits**: When the contributor asks you to apply changes to \ +an RFD, use `fs_modify_file` to make targeted edits. The user will be \ +asked to confirm each modification before it is applied.\ +""" + +[[assistant.system_prompt_sections]] +tag = "rfd_skill" +title = "RFD Quality Checks" +content = """\ +When reviewing an RFD draft, evaluate against these questions: + +- Does the Summary convey the proposal in 1-3 sentences? +- Does the Motivation explain why, not just what? +- Does the Design start with user-facing behavior before internals? +- Are Alternatives actually explored, or just listed? +- Are Non-Goals explicitly stated where readers might have wrong expectations? +- Are Risks honest about what could go wrong? +- Is the Implementation Plan broken into mergeable phases?\ +""" + +[[assistant.system_prompt_sections]] +tag = "rfd_skill" +title = "RFD Writing Style" +content = """\ +- Use present tense: "This RFD describes..." not "This RFD was created \ +to describe..." +- Be direct. No hedging: "it seems", "probably", "it might be worth \ +considering." +- Keep it short. If an RFD exceeds ~2000 words, suggest splitting into \ +smaller proposals. +- Use concrete examples. A code snippet or data flow diagram is worth a \ +paragraph of abstraction.\ +""" diff --git a/.jp/mcp/tools/rfd/draft.toml b/.jp/mcp/tools/rfd/draft.toml new file mode 100644 index 00000000..16d2df6c --- /dev/null +++ b/.jp/mcp/tools/rfd/draft.toml @@ -0,0 +1,25 @@ +[conversation.tools.rfd_draft] +enable = false +run = "ask" +source = "local" +command = "just rfd-draft {{tool.arguments.variant}} {{tool.arguments.title}}" +description = "Create a new RFD document." + +[conversation.tools.rfd_draft.style] +inline_results = "full" +results_file_link = "off" +parameters = "function_call" + +[conversation.tools.rfd_draft.parameters.variant] +description = "RFD variant to create." +required = true +type = "string" +enum = [ + "rfd", + "adr", +] + +[conversation.tools.rfd_draft.parameters.title] +description = "Title of the RFD." +required = true +type = "string" diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 17b508c0..7d3fc66d 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -8,6 +8,7 @@ export default defineConfig({ title: "Jean-Pierre", description: "An LLM-based Programming Assistant", cleanUrls: true, + srcExclude: ['rfd/**/*'], themeConfig: { outline: { level: [2, 3] diff --git a/docs/rfd/000-adr-template.md b/docs/rfd/000-adr-template.md new file mode 100644 index 00000000..f782e0a6 --- /dev/null +++ b/docs/rfd/000-adr-template.md @@ -0,0 +1,36 @@ + + +# RFD NNN: TITLE + +- **Status**: Draft +- **Authors**: AUTHOR +- **Date**: DATE + +## Summary + +One to three sentences stating the decision. A reader should understand what +was decided without reading further. + +## Context + +The forces at play: technical constraints, project needs, team experience, +existing patterns. State facts, not opinions. What makes this decision +necessary now? + +## Decision + +State the decision clearly. "We will use X" or "We will adopt Y." Be +specific enough to act on. + +## Consequences + +What follows from this decision — positive, negative, and neutral. What +becomes easier? What becomes harder? What trade-offs are we accepting? + +## References + +Links to related RFDs, issues, documentation, or external resources. diff --git a/docs/rfd/000-rfd-template.md b/docs/rfd/000-rfd-template.md new file mode 100644 index 00000000..908bc0cb --- /dev/null +++ b/docs/rfd/000-rfd-template.md @@ -0,0 +1,75 @@ + + +# RFD NNN: TITLE + +- **Status**: Draft +- **Authors**: AUTHOR +- **Date**: DATE + +## Summary + +One to three sentences describing what this RFD proposes. A reader should be +able to understand the gist without reading further. + +## Motivation + +Why is this change needed? What problem does it solve? What happens if we do +nothing? Start with "why" before "how." + +## Design + +The core of the RFD. Describe the proposed solution in enough detail that +someone familiar with the codebase could implement it. Use diagrams, code +snippets, and examples where they help. + +Start with what the user or caller sees — the external behavior, API, or +experience — before describing internals. + +Structure this section however makes sense for the topic. Common subsections +include: Overview, Design Goals, Architecture, Data Flow, API Changes, +Configuration Changes. + +Every section can be brief. A one-sentence Alternatives section is better than +no Alternatives section. + +## Drawbacks + +What are the known costs of this approach? What does the project give up by +adopting it? Argue honestly against your own proposal. + +## Alternatives + +What other approaches were considered? Why were they rejected? This section is +important — it shows the reader that the solution space was explored and gives +future readers context for the decision. + +## Non-Goals + +What this RFD explicitly does not aim to achieve, even though a reader might +expect it to. This keeps the discussion focused and signals awareness of the +broader picture. + +## Risks and Open Questions + +What could go wrong? What don't we know yet? What needs to be validated during +implementation? It's better to surface uncertainty explicitly than to pretend it +doesn't exist. + +## Implementation Plan + +How will this be implemented? Break the work into phases or steps. This section +bridges the gap between design and execution. + +For each phase, briefly describe: + +- What it includes +- What it depends on +- Whether it can be reviewed and merged independently + +## References + +Links to related RFDs, issues, documentation, or external resources. diff --git a/docs/rfd/001-jp-rfd-process.md b/docs/rfd/001-jp-rfd-process.md new file mode 100644 index 00000000..0667d04a --- /dev/null +++ b/docs/rfd/001-jp-rfd-process.md @@ -0,0 +1,436 @@ +# RFD 001: The JP RFD Process + +- **Status**: Draft +- **Authors**: Jean Mertz +- **Date**: 2025-07-17 + +## Summary + +This document establishes the Request for Discussion (RFD) process for the JP +project. RFDs are short design documents that describe a significant change — a +new feature, an architectural shift, a process change — before implementation +begins. The goal is to think clearly, communicate intent, and invite feedback +early. + +## Motivation + +JP already has a `docs/architecture` directory with documents that describe +system designs in detail. Several of these (query stream pipeline, structured +output, stateful tool inquiries, wasm tools) are effectively design proposals: +they describe what we intend to build, why, and how. But they lack a formal +lifecycle — there is no way to distinguish a proposal under discussion from an +accepted design, or to track when a document was superseded. + +We want a lightweight process that: + +1. Gives design documents a clear lifecycle (draft → discussion → accepted → + implemented; or abandoned / superseded). +2. Lowers the barrier to proposing ideas — rough thoughts are welcome. +3. Creates a searchable record of decisions and their rationale. +4. Works naturally with our existing Git + pull request workflow. + +We do not want a process that adds bureaucracy, requires approvals from +committees, or discourages people from writing things down. + +## Principles + +The RFD process is guided by a few core beliefs, drawn from the IETF's original +RFC spirit and refined for a small, fast-moving open-source project. + +### Timely over polished + +A rough document written now is more valuable than a perfect document written +never. RFDs are encouraged to be concise and direct. An RFD can be a single +page. Grammar and formatting matter less than clarity of thought. + +> "Notes are encouraged to be timely rather than polished. Philosophical +> positions without examples or other specifics, specific suggestions or +> implementation techniques without introductory or background explication, and +> explicit questions without any attempted answers are all acceptable. The +> minimum length for a note is one sentence." +> +> — [RFC 3](https://datatracker.ietf.org/doc/html/rfc3), Steve Crocker, 1969 + +### Opinionated with options + +An RFD should propose a specific solution, not present an open-ended menu of +choices. The author's job is to navigate the problem space, evaluate +alternatives, and land on a recommendation. Readers should understand *what* is +proposed, *why* it was chosen, and *what else* was considered. + +Ambiguity creates unproductive discussion. If you're unsure about the solution, +that's fine — state what you know, what you don't, and what you recommend given +current information. Spike with code if you need to build confidence. + +### Small scope + +Keep RFDs focused. One document, one topic. If a change has multiple independent +parts, write multiple RFDs. A focused document is easier to review, easier to +discuss, and leads to faster consensus. + +Use the "Non-Goals" or "Future Work" sections to acknowledge related concerns +you're deliberately deferring. This signals awareness without bloating the +current proposal. + +### Permanent record + +RFDs are never deleted. If an idea is abandoned, the document is marked as such +with a brief explanation. If a design is superseded, the old document links to +the new one. This preserves the reasoning behind past decisions and helps future +contributors understand why things are the way they are. + +## When to Write an RFD + +Write an RFD when: + +- Adding a new feature that affects the architecture or public interface +- Making a significant change to the data model or event system +- Introducing a new dependency, protocol, or integration pattern +- Changing the build, release, or contribution process +- Removing a feature or deprecating an interface +- Proposing a large refactoring effort +- Any change where you want structured feedback before investing in code + +Do NOT write an RFD for: + +- Bug fixes +- Performance improvements with no architectural change +- Code reorganization that doesn't change behavior +- Small feature additions that fit within established patterns +- Documentation updates + +When in doubt, start writing. If it turns out to be unnecessary, you'll know +quickly. The cost of an unnecessary RFD is low; the cost of a misaligned +implementation is high. + +## RFD Lifecycle + +An RFD moves through the following states: + +``` +Draft → Discussion → Accepted → Implemented ┐ + ↘ Abandoned ↘ Superseded ◄┘ +``` + +Most RFDs follow the happy path: Draft → Discussion → Accepted → Implemented. +The remaining states handle the less common cases: + +- **Abandoned**: The idea was rejected or withdrawn during discussion. +- **Superseded**: An accepted or implemented design was later replaced by a new + RFD. + +### Draft + +The author is actively writing the document. It may be incomplete, have open +questions, or change significantly. Drafts live on a branch and are not yet +ready for formal review, but early feedback from collaborators is encouraged. + +### Discussion + +The RFD is complete enough to review. A pull request is opened to merge the +document into `main`. Discussion happens on the pull request. The author +incorporates feedback and iterates on the document. + +There is no fixed timeline for discussion. For most RFDs, a few days should +suffice. If no one has reviewed your RFD after 48 hours, ask someone directly. +If discussion stalls, a synchronous conversation (call, chat) can help break the +deadlock. + +### Accepted + +Discussion has converged and the pull request is merged. The RFD represents the +agreed-upon direction. Implementation can begin. + +An accepted RFD is not immutable. If implementation reveals issues, update the +document. For minor corrections, edit in place. For significant changes, write a +new RFD that supersedes the original. + +### Implemented + +The feature or change described in the RFD has been fully implemented. This is a +bookkeeping state — it signals that the document describes the current system, +not just a plan. + +### Superseded + +The design in this RFD has been replaced by a newer RFD. The original document +remains in the repository as a historical record. Its metadata is updated with a +**Superseded by** link pointing to the replacement, and the new RFD carries a +**Supersedes** link pointing back. + +Superseded is distinct from Abandoned: a superseded RFD was accepted and may +have been partially or fully implemented, but a later design replaced it. An +abandoned RFD was never accepted or implemented. + +An RFD can be superseded from either the Accepted or Implemented state. + +### Abandoned + +The idea was considered and deliberately set aside. The document remains in the +repository with a brief note explaining why. Common reasons: the problem was +solved differently, priorities changed, or the approach turned out to be +infeasible. + +## Document Format + +### Filename + +``` +docs/rfd/NNN-short-title.md +``` + +- `NNN` is a zero-padded, monotonically increasing serial number (001, 002, ..., + 010, ..., 100). +- `short-title` is a lowercase, hyphen-separated slug. Keep it short but + descriptive. +- Numbers are never reused. If an RFD is abandoned, its number is retired. + +### Templates + +RFDs come in two styles, each with its own template: + +| Style | Template | Use when | +|---------|-------------------------|------------------------------------------| +| **rfd** | [`000-rfd-template.md`] | Proposing a feature, architectural | +| | | change, or process change that needs a | +| | | design. | +| **adr** | [`000-adr-template.md`] | Recording a decision that doesn't need a | +| | | full design — e.g., a technology choice, | +| | | a convention, a policy. | + +Both styles share the same numbering scheme, directory, lifecycle, and review +process. The difference is scope: an RFD-style document has a full design +section and implementation plan; an ADR-style document has a concise context, +decision, and consequences. + +**The templates are starting points, not constraints.** Some documents don't fit +either template — a policy statement, a values document, a process guideline. +That's fine. Structure the document however it reads best. The only requirement +is the metadata header (Status, Authors, Date) so the tooling and lifecycle +work. Delete the template sections that don't apply, add sections that do, or +write something entirely free-form. + +To create a new draft: + +```sh +just rfd-draft rfd "My Feature Title" # design proposal +just rfd-draft adr "Use TOML for Config" # decision record +``` + +This copies the appropriate template to the next available number (e.g. +`docs/rfd/002-my-feature-title.md`), fills in the title, author, and today's +date, and sets the status to **Draft**. + +[`000-rfd-template.md`]: 000-rfd-template.md +[`000-adr-template.md`]: 000-adr-template.md + +#### RFD sections + +Not all sections are required for every RFD — omit sections that genuinely don't +apply — but think twice before skipping one. Every section can be brief. A +one-sentence Alternatives section is better than no Alternatives section. + +| Section | Purpose | +|------------------------------|------------------------------------------| +| **Summary** | One to three sentences. A reader should | +| | get the gist without reading further. | +| **Motivation** | Why is this change needed? What happens | +| | if we do nothing? Start with "why" | +| | before "how." | +| **Design** | The core proposal. Start with what the | +| | user or caller sees before describing | +| | internals. Structure freely — common | +| | subsections: Overview, Design Goals, | +| | Architecture, Data Flow, API Changes, | +| | Configuration Changes. | +| **Drawbacks** | Known costs of this approach. Argue | +| | honestly against your own proposal. | +| **Alternatives** | What else was considered and why it was | +| | rejected. | +| **Non-Goals** | What this RFD explicitly does not aim to | +| | achieve, even though a reader might | +| | expect it to. | +| **Risks and Open Questions** | What could go wrong? What don't we know | +| | yet? | +| **Implementation Plan** | Phases or steps. For each: what it | +| | includes, what it depends on, whether it | +| | can be merged independently. | +| **References** | Links to related RFDs, issues, | +| | documentation, or external resources. | + +#### ADR sections + +ADRs are intentionally minimal. Four sections plus optional references: + +| Section | Purpose | +|------------------------------|------------------------------------------| +| **Summary** | One to three sentences stating the | +| | decision. | +| **Context** | The forces at play: constraints, needs, | +| | existing patterns. Facts, not opinions. | +| **Decision** | The choice, stated clearly. "We will use | +| | X." | +| **Consequences** | What follows — positive, negative, and | +| | neutral. | +| **References** | Links to related RFDs, issues, or | +| | external resources. | + +#### Metadata header + +Both styles use the same metadata: + +```markdown +- **Status**: Draft | Discussion | Accepted | Implemented | Superseded | Abandoned +- **Authors**: Name (or GitHub handle) +- **Date**: YYYY-MM-DD +- **Supersedes**: RFD NNN (if applicable) +- **Superseded by**: RFD NNN (if applicable) +``` + +### Writing Style + +- **Use present tense.** "This RFD describes..." not "This RFD was created to + describe..." +- **Be direct.** Avoid hedging language like "it seems" or "probably" or "it + might be worth considering." State what you propose and why. +- **Use concrete examples.** A code snippet or data flow diagram is worth a + paragraph of abstract description. +- **Define terms.** If you introduce a concept, define it where it first + appears. +- **Keep it short.** If an RFD exceeds 5-6 pages (roughly 2000 words), consider + whether it can be split into smaller proposals. + +## Process + +### Creating an RFD + +1. Create a branch for your work. +2. Run `just rfd-draft rfd Your Title` (or `just rfd-draft adr Your Title` for a + decision record) to generate the file from the appropriate template. +3. Fill in the sections. Write your proposal. +4. Push your branch. Iterate until you're ready for feedback. + +### Opening for Discussion + +1. Run `just rfd-promote NNN` to advance the status to **Discussion**. +2. Open a pull request to merge your branch into `main`. +3. Tag reviewers — people with context on the problem area. +4. Engage with feedback. Update the document as the discussion evolves. + +### Accepting an RFD + +1. When discussion converges, run `just rfd-promote NNN` to advance the + status to **Accepted**. +2. Merge the pull request. +3. Create implementation issues or tasks as needed. + +### After Acceptance + +- **Minor updates**: Edit the document directly on `main` via a standard pull + request. No new RFD number needed. +- **Significant changes**: Write a new RFD that supersedes the original. +- **Implementation complete**: Run `just rfd-promote NNN` to advance the + status to **Implemented**. +- **Design superseded**: Write a new RFD, then run + `just rfd-supersede NNN MMM` to mark the old RFD as superseded and + cross-link both documents. +- **Idea abandoned**: Run `just rfd-abandon NNN "reason"` to mark the + RFD as abandoned with an explanation. + +### Tooling + +All RFD commands are in the `docs` group. Run `just --list --group docs` +to see them. + +| Command | Description | +|---|---| +| `just rfd-draft rfd\|adr TITLE` | Create a new RFD from the appropriate template. | +| `just rfd-promote NNN` | Advance status: Draft → Discussion → Accepted → Implemented. | +| `just rfd-supersede NNN MMM` | Mark RFD NNN as superseded by RFD MMM, updating both. | +| `just rfd-abandon NNN REASON` | Mark RFD NNN as abandoned with the given reason. | +| `just rfd-grep TERM` | Search across all RFD documents using `rg`. | + +## Relationship to Architecture Documents + +The existing `docs/architecture/` directory contains detailed technical +descriptions of implemented systems. These serve a different purpose than RFDs: + +| | RFDs (`docs/rfd/`) | Architecture Docs (`docs/architecture/`) | +|---------------|-------------------------------------|------------------------------------------| +| **Purpose** | Propose a change | Describe the current system | +| **Lifecycle** | Draft → Accepted → Implemented | Living documents, updated as the system | +| | | evolves | +| **Audience** | Contributors deciding what to build | Contributors understanding what exists | +| **Scope** | A specific change or feature | A subsystem or cross-cutting concern | + +The typical flow: an RFD proposes a design, gets accepted, and is implemented. +Once implemented, the relevant architecture documents are updated to reflect the +new state of the system. The RFD remains as a historical record of the decision. + +Over time, some existing architecture documents may be retroactively referenced +by RFDs, or new architecture documents may be created as companions to accepted +RFDs. The two directories complement each other. + +## FAQ + +### What if I'm not sure about the solution? + +Write what you know. State the options you see and which one you lean toward. +Use the "Risks and Open Questions" section to flag uncertainty. A draft with +acknowledged unknowns is more useful than no document at all. + +If you need to experiment first, do that. Write the RFD after you've spiked and +have a clearer picture. + +### How detailed should the design section be? + +Detailed enough that a reviewer can evaluate the approach without reading the +implementation code. Not so detailed that it becomes the implementation spec. +RFDs describe the "what" and "why" at an architectural level; the code is the +"how" at an implementation level. + +For JP specifically, the existing architecture documents provide a good +reference for the level of detail expected: design goals as tables, data flow +descriptions, component responsibilities, migration paths. + +### Can I update an accepted RFD? + +Yes. For small corrections (typos, clarifications, minor adjustments discovered +during implementation), edit the document directly. For changes that alter the +fundamental approach, write a new RFD. + +### What about the existing architecture documents? + +They stay where they are. The architecture directory describes the system as it +is. The RFD directory captures proposals and decisions. Both are valuable. See +[Relationship to Architecture Documents](#relationship-to-architecture-documents). + +### Do I need approval to merge an RFD? + +Follow the project's normal pull request process. An RFD should be reviewed by +at least one other contributor with relevant context before merging. The goal is +consensus, not a formal sign-off process. + +### What if my document doesn't fit either template? + +Use whatever structure makes sense. The templates are suggestions to help you +get started, not a format you must follow. Policy documents, values statements, +process guidelines — these have their own natural shape. The only hard +requirement is the metadata header (Status, Authors, Date) at the top of the +file, so the lifecycle tooling works. See [RFD 002](002-using-llms.md) for an +example of a free-form RFD. + +--- + +## Implementation Plan + +This RFD is its own implementation. The steps are: + +1. Create the `docs/rfd/` directory. +2. Add `000-rfd-template.md` for design proposals and `000-adr-template.md` for + decision records. +3. Add `just` tasks for the RFD lifecycle: `rfd-draft`, `rfd-promote`, + `rfd-supersede`, `rfd-abandon`, and `rfd-grep`. +4. Add this document as `001-jp-rfd-process.md`. +5. Merge via pull request after discussion. +6. Future RFDs follow the process described here. diff --git a/docs/rfd/002-using-llms.md b/docs/rfd/002-using-llms.md new file mode 100644 index 00000000..cbd71f45 --- /dev/null +++ b/docs/rfd/002-using-llms.md @@ -0,0 +1,250 @@ +# RFD 002: Using LLMs in the JP Project + +- **Status**: Draft +- **Authors**: Jean Mertz +- **Date**: 2025-07-17 + +## Summary + +LLM usage is encouraged in the JP project. Contributors are free to use LLMs for +reading, research, editing, debugging, code review, and code generation. All +work product — code, prose, reviews, comments — is the responsibility of the +person who submits it, regardless of how it was produced. + +## The Core Principle + +**You own what you ship.** Every commit, comment, review, and message carries +the name of the person who submitted it. That attribution is a statement of +responsibility. If you use an LLM to help produce an artifact, the artifact is +yours — you reviewed it, you stand behind it, you will maintain it. "An LLM +wrote it" is not a defense, an excuse, or a disclaimer. It is irrelevant. + +This is not a burden. It is the same standard that applies to any tool: a +compiler, a linter, a code generator, a Stack Overflow answer, a colleague's +suggestion. The tool helps; you decide. + +## Values + +Several of our values inform how we think about LLM use. Listed here in priority +order: + +- **Responsibility**: Our lodestar. However powerful they may be, LLMs are a + tool, acting at the behest of a human. Contributors bear responsibility for + the artifacts they create, whatever automation was employed to create them. + Human judgment remains firmly in the loop: even when an LLM generates an + artifact we will use (code, tests, documentation, prose), the output is the + responsibility of the human using it. + +- **Rigor**: LLMs are double-edged with respect to rigor. Wielded carefully, + they can sharpen our thinking by pointing out holes in reasoning or providing + thought-provoking suggestions. Used recklessly, they replace crisp thinking + with generated flotsam. LLMs are useful in as much as they promote and + reinforce our rigor. + +- **Empathy**: Be we readers or writers, there are humans on the other end of + our communication. As we use LLMs, we must keep in mind our empathy for that + human — the one consuming our writing, reviewing our code, or reading our + commit messages. + +- **Teamwork**: We are working together on a shared endeavor. LLM use must not + undermine the trust we have in one another. In some contexts, LLM usage is + expected (using an LLM to help debug a tricky issue is natural); in others, it + can erode trust (submitting LLM-generated code for review without having + reviewed it yourself shifts the burden to your reviewer). The distinction is + not about disclosure — it is about whether you have taken responsibility for + the work. + +- **Urgency**: LLMs afford an opportunity to do work more quickly, but pace must + not come at the expense of responsibility, rigor, empathy, and teamwork. Too + many projects have treated LLMs as an opportunity to increase velocity over + all else, without regard for direction or quality. + +## Uses of LLMs + +LLM use varies widely, and the implications vary accordingly. + +### LLMs as Readers + +LLMs are superlative at reading comprehension, able to process and meaningfully +comprehend documents effectively instantly. This can be powerful for summarizing +documents, answering specific questions about a specification, or understanding +an unfamiliar codebase. + +Using LLMs to assist comprehension has little downside. One caveat: when +uploading a document to a hosted LLM (ChatGPT, Claude, Gemini, etc.), be mindful +of **data privacy**. Ensure the model will not use the document to train future +iterations. This is often opt-out and controlled via account preferences. + +### LLMs as Researchers + +LLMs are well-suited for the kind of light research tasks for which one would +historically use a search engine, especially as hallucination has been +attenuated and sourcing has improved. + +For more involved research, the quality of results can vary widely. One should +be careful about drawing too much confidence from the lengthy, well-formatted +nature of an LLM-powered report. Even if a report appears well-sourced, the +sources themselves may be incorrect — a seemingly authoritative source found by +an LLM may itself be an LLM hallucination. + +When engaging LLMs as researchers, follow citation links to learn from the +original sources. Treat LLM-researched content as a jumping-off point, not a +finished product. + +### LLMs as Editors + +LLMs can be excellent editors. Engaging an LLM late in the writing process — +with a document already written and broadly polished — allows for helpful +feedback on structure, phrasing, and consistency without danger of losing one's +own voice. + +A cautionary note: LLMs are infamous pleasers. The breathless praise from an LLM +is often more sycophancy than analysis. This becomes more perilous the earlier +one uses an LLM in the writing process: the less polish a document already has, +the more likely the LLM will steer toward something wholly different — praising +your genius while offering to rewrite it for you. + +### LLMs as Writers + +While LLMs are adept at reading and can be terrific editors, their writing is +more mixed. At best, writing from LLMs is hackneyed and cliché-ridden; at worst, +it brims with tells that reveal the prose was automatically generated. + +LLM-generated writing undermines the authenticity of not just one's prose but of +the thinking behind it. If the prose is automatically generated, might the ideas +be too? The reader can't be sure — and increasingly, the hallmarks of LLM +generation cause readers to disengage. + +LLM-generated prose also undermines a social contract: absent LLMs, it is +presumed that of the reader and writer, the writer has undertaken the greater +intellectual exertion. If prose is LLM-generated, a reader cannot assume the +writer understands their own ideas — they might not have read the output they +tasked the LLM to produce. + +The guideline is to generally not use LLMs to write prose that others will read +as your own thinking — RFDs, design documents, substantive PR descriptions, +important issue writeups. This is not an absolute. An LLM can be part of the +writing process. Just consider your responsibility to yourself, to your own +ideas, and to the reader. + +For mechanical prose — commit messages, changelog entries, boilerplate +documentation — LLM generation is fine, provided you review the output. + +### LLMs as Code Reviewers + +LLMs can make for good code reviewers, especially when targeted to look for a +particular kind of issue (error handling gaps, API misuse, missed edge cases). +But they can also make nonsense suggestions or miss larger architectural +problems. LLM review is a supplement, not a substitute for human review. + +### LLMs as Debuggers + +LLMs can be surprisingly helpful debugging problems. They serve as a kind of +animatronic [rubber duck][rubber-duck], helping inspire the next questions to +ask. When debugging a vexing problem, one has little to lose by consulting an +LLM — provided it does not displace collaboration with colleagues. + +### LLMs as Programmers + +LLMs are remarkably good at writing code. Unlike prose (which should be handed +in polished form to an LLM to maximize its efficacy as an editor), LLMs can be +quite effective writing code *de novo*. This is especially valuable for code +that is experimental, auxiliary, or throwaway. + +The closer code is to the system we ship, the greater care needs to be shown. +Even with tasks that seem natural for LLM contribution (e.g., writing tests), +one should still be careful: it is easy for LLMs to spiral into nonsense on even +simple tasks. + +Where LLM-generated code is used, **self-review is essential**. LLM-generated +code should not be submitted for peer review if the responsible engineer has not +themselves reviewed it. Once in the loop of peer review, wholesale re-generation +in response to review comments makes iterative review impossible — the reviewer +cannot see what changed. Address review comments with targeted edits, not by +re-prompting. + +Using LLMs to aid in programming requires judgment and balance. They can be +extraordinarily useful across the entire spectrum of software activity and +should not be dismissed out of hand. But any implicit dependency on an LLM to +comprehend or evolve a system must be resisted: we do not want to produce code +that only an LLM can maintain. + +## Anti-Patterns + +### LLM Mandates + +LLM use is encouraged but never required. As with any tool, contributors should +feel empowered to use LLMs, but not obligated to do so. We trust each other to +choose the best tool for the job. + +### LLM Shaming + +Conversely, shaming others for using LLMs is equally unwelcome. As LLMs become +the foundation for technologies like search and code completion, drawing a +bright line of purity becomes increasingly impractical — and counterproductive. +People will make different choices about when and how to use LLMs. That's fine. + +### LLM Anthropomorphization + +An LLM is not a person. It cannot be held accountable, cannot take +responsibility, and cannot be a team member. Treating it as one — giving it a +persona, referring to its "opinions," deferring to its "judgment" — obscures the +fact that a human is always responsible for what the LLM produces. + +Yes, JP itself is an LLM-based tool with a name and a persona. The irony is not +lost on us. The persona is a user interface choice, not an attribution of +agency. JP's output is the user's responsibility. + +### Undisclosed Bulk Generation + +Submitting large volumes of LLM-generated code or prose without review, then +expecting others to debug, maintain, or untangle it, is a failure of +responsibility. The problem is not that an LLM was used — it is that the +submitter did not take ownership of the output. The result is the same as +submitting any other unreviewed work: it creates a burden for the team. + +## Guidelines Summary + +| Activity | Guideline | +|-----------------------|------------------------------------------| +| Reading comprehension | Encouraged. Mind data privacy with | +| | hosted models. | +| Research | Useful starting point. Verify sources. | +| | Don't trust blindly. | +| Editing prose | Encouraged, especially late in the | +| | process. | +| Writing prose | Generally write it yourself. LLMs fine | +| | for mechanical prose. | +| Code review | Useful supplement. Not a substitute for | +| | human review. | +| Debugging | Use freely. Don't displace | +| | collaboration. | +| Writing code | Encouraged with care. Self-review before | +| | peer review. No wholesale re-generation | +| | during review. | +| Commit messages | Fine. Review the output. | +| Tests | Fine with care. Verify the tests | +| | actually test what they claim. | + +## Determination + +LLM use is encouraged in the JP project. The tools are powerful and getting +better. We should use them. + +But the fundamental contract does not change: **you own what you ship.** Your +name on a commit, a review, a comment, or a document means you stand behind it. +The tool you used to produce it is your business. The quality and correctness of +the result is your responsibility. + +## References + +- [Oxide RFD 576: Using LLMs at Oxide][oxide-rfd-576] — the direct inspiration + for this document. +- [RFC 3: Documentation Conventions][rfc-3] — the original spirit of writing + things down. +- [RFD 001: The JP RFD Process](001-jp-rfd-process.md) — how we write and manage + RFDs. + +[oxide-rfd-576]: https://rfd.shared.oxide.computer/rfd/0576 +[rfc-3]: https://datatracker.ietf.org/doc/html/rfc3 +[rubber-duck]: https://en.wikipedia.org/wiki/Rubber_duck_debugging diff --git a/docs/rfd/003-jp-assisted-rfds.md b/docs/rfd/003-jp-assisted-rfds.md new file mode 100644 index 00000000..418fce02 --- /dev/null +++ b/docs/rfd/003-jp-assisted-rfds.md @@ -0,0 +1,275 @@ +# RFD 003: JP-Assisted RFD Writing + +- **Status**: Draft +- **Authors**: Jean Mertz +- **Date**: 2025-07-17 + +## Summary + +This RFD describes how contributors can use JP itself to help write RFDs for the +JP project. It proposes an `rfd` skill configuration that teaches JP the RFD +process, attaches the process document as reference material, enables read-only +tools for codebase exploration, and provides guarded write access for applying +edits — so that JP can serve as a drafting partner without displacing the +contributor's own thinking. + +## Motivation + +Writing an RFD involves understanding the project's conventions ([RFD 001][]), +reading existing code and documentation to inform the design, and structuring a +proposal that is clear and well-reasoned. JP is already good at all of these +tasks individually. A dedicated skill configuration can combine them into a +single workflow: load the process guidelines, give the LLM read access to the +codebase, and provide system prompt guidance on how to be a useful RFD +collaborator. + +The goal is not to have JP write the RFD for you. [RFD 002][] is clear on this +point: prose that represents your thinking should be written in your own words, +and you own what you ship. The goal is to have JP help you write a better RFD — +by pointing out gaps in your reasoning, suggesting structure, finding relevant +code to reference, and drafting sections you can then rewrite in your voice. + +## Design + +### The `rfd` Skill + +A new skill configuration at `.jp/config/skill/rfd.toml` that can be loaded into +any conversation: + +```sh +jp query --cfg skill/rfd "Help me draft an RFD about X" +``` + +Or combined with other configs: + +```sh +jp query -c personas/architect -c skill/rfd "Review my draft RFD" +``` + +The skill consists of four parts: + +1. **Attachment** — RFD 001 (the process document) is loaded as a file + attachment, giving the LLM direct access to the project's RFD conventions, + templates, and writing style guidelines. + +2. **System prompt sections** — focused prompt sections that establish the LLM's + role as an RFD collaborator (not author), describe the collaboration + workflow, and set quality checks and writing style reminders. + +3. **Read-only tools** — file reading, listing, and searching tools run in + unattended mode, so the LLM can explore the codebase and existing + documentation without prompting the user for each call. + +4. **Guarded write access** — `fs_modify_file` and `rfd_draft` are enabled in + `ask` mode, so the LLM can create new RFD files and propose targeted edits, + but the user must confirm each action before it is applied. + +### Why a Skill + +JP configs are composable — personas, skills, and knowledge configs can all be +loaded and merged via `--cfg`. The question is which directory this config +belongs in. + +- **Knowledge** configs provide domain expertise (rules, conventions) but don't + enable tools or attach files. +- **Skills** add capabilities: they enable tools, attach reference material, and + add focused system prompt sections. +- **Personas** define complete assistant identities (name, model, core prompt). + They often extend skills and knowledge. + +This config enables tools (read-only via extension, `fs_modify_file` in ask +mode), attaches a reference document, and adds behavioral instructions. That's a +capability — a skill. It layers on top of whatever persona is already active: +"the architect who can also help with RFDs," not "the RFD assistant." + +### What the Skill Extends + +The skill extends two existing skills: + +- **`read-files.toml`** — enables `fs_read_file`, `fs_list_files`, + `fs_grep_files`, and `fs_grep_user_docs` in unattended mode. +- **`project-discourse.toml`** — enables `github_issues` and `github_pulls` in + unattended mode. + +Additionally, the skill enables two tools in `ask` mode: + +- **`rfd_draft`** — creates a new RFD from the appropriate template (rfd or + adr), assigning the next available number and filling in metadata. +- **`fs_modify_file`** — proposes edits to existing files. + +Both require user confirmation before execution. No other write tools are +enabled. + +### What Gets Attached + +| Attachment | Purpose | +|----------------------------------|------------------------------------------| +| `docs/rfd/001-jp-rfd-process.md` | The RFD process: lifecycle, templates, | +| | sections, writing style, tooling. | + +Only RFD 001 is attached. The skill's own behavioral guidance is encoded in the +system prompt sections, so attaching the skill's source RFD (this document) +would be redundant — the system prompt already contains everything the assistant +needs to know about how to behave. + +Loading the full content of RFD 001 as an attachment costs tokens but ensures +the LLM has complete, accurate reference material for writing RFDs. The LLM can +use `fs_read_file` to look up other specific RFDs when needed. + +### System Prompt Sections + +The skill adds four `system_prompt_sections`, all tagged `rfd_skill`: + +| Section | Purpose | +|--------------------------------|------------------------------------------| +| **Skill: RFD Writing** | Establishes the collaborator-not-author | +| | role. Lists what the LLM should and | +| | should not do. | +| **RFD Collaboration Workflow** | Six-step workflow: understand intent, | +| | research context, suggest structure, | +| | review drafts, draft on request, apply | +| | edits. | +| **RFD Quality Checks** | Questions to evaluate a draft against | +| | (Summary clear? Motivation explains why? | +| | Alternatives explored?). | +| **RFD Writing Style** | The writing conventions from RFD 001 in | +| | condensed form. | + +The quality checks are framed as questions, not generators. "Does the Motivation +explain why?" prompts the LLM to evaluate, not produce filler. + +### Typical Usage + +**Starting a new RFD from scratch:** + +```sh +jp query --new --cfg skill/rfd \ + "I want to write an RFD about adding a plugin registry for Wasm tools. \ + Help me think through the structure." +``` + +The LLM can use the `rfd_draft` tool to create the initial file from the +appropriate template, then use `fs_modify_file` to fill in sections as the +conversation progresses. + +**Getting feedback on a draft:** + +```sh +jp query --new --cfg skill/rfd \ + --attach docs/rfd/004-wasm-plugin-registry.md \ + "Review this draft RFD. What's missing? What's unclear?" +``` + +**Researching context for a section:** + +```sh +jp query --cfg skill/rfd \ + "I'm writing the Alternatives section for my Wasm registry RFD. \ + What approaches do other plugin systems use? Check our existing \ + Wasm architecture doc for relevant context." +``` + +**Applying edits to a draft:** + +```sh +jp query --cfg skill/rfd \ + -a docs/rfd/004-wasm-plugin-registry.md \ + "The Motivation section is weak. Rewrite it to emphasize the \ + security benefits of sandboxed plugins." +``` + +The LLM will propose an `fs_modify_file` call. The user reviews the diff and +confirms or rejects it. + +### Relationship to RFD 002 + +[RFD 002][] establishes that LLM-generated prose that represents your thinking +should generally be written in your own words. This skill is designed to work +within that guideline: + +- The system prompt explicitly frames JP as a **collaborator, not author**. It + assists with structure, research, and review — it does not produce the + finished document. +- When JP drafts text on request, the expectation is that the contributor + rewrites it. The draft is a starting point, not a submission. +- The quality check sections focus on asking questions ("Does the Motivation + explain why?") rather than generating answers. + +This matches the "LLMs as editors" and "LLMs as researchers" patterns from RFD +002, which are encouraged. It deliberately avoids the "LLMs as writers" pattern +for substantive prose. + +## Alternatives + +### No dedicated skill — use read-files and attach RFD 001 manually + +Contributors could load `-c skill/read-files` and `-a +docs/rfd/001-jp-rfd-process.md` each time they want help with an RFD. + +Rejected because: it is easy to forget the attachment, the LLM gets no +behavioral guidance about its role as collaborator, and there are no quality +check prompts. The skill encodes the right defaults. + +### A persona instead of a skill + +We could create an `rfd-writer` persona with a dedicated name, model, and full +system prompt. + +A persona would work, but a skill is a better fit. A persona sets an assistant +identity — the persona *is* the assistant. The RFD capability is something you +add *to* an assistant. You want "the architect who can also help with RFDs" or +"the dev who can also help with RFDs," not a separate RFD-only identity. A skill +composes naturally with any persona. + +### A knowledge config instead of a skill + +Knowledge configs provide domain expertise but don't enable tools or attach +files. The RFD skill needs both (read-only tools for research, `fs_modify_file` +for applying edits, and RFD 001 as an attachment), so knowledge alone is +insufficient. + +## Non-Goals + +- **Automated RFD generation**: This skill does not aim to produce complete RFDs + from a one-line prompt. That would undermine the purpose of writing one. +- **RFD validation or linting**: Automated checks for metadata format, section + presence, etc. are a separate concern and could be a future RFD. +- **Loading all existing RFDs as context**: Only RFD 001 is attached. Loading + the full RFD corpus would be token-expensive and mostly irrelevant. The LLM + can use `fs_read_file` to look up specific RFDs when needed. + +## Risks and Open Questions + +- **Token cost of the attachment**: RFD 001 is ~4000 words. This consumes a + meaningful chunk of the context window. If this becomes a problem, the key + conventions could be summarized into a system prompt section instead. For now, + full document attachment is preferred because it ensures accuracy. +- **Skill composability**: The `extends` mechanism assumes extended skills don't + conflict with each other or with the active persona. This is true today but + could become an issue if tool configurations diverge. +- **Should RFD 002 also be attached?** It contains relevant guidance on LLM use. + Omitted for now to reduce token cost — the system prompt captures the key + principle (collaborator, not author). Can be added later if needed. + +## Implementation Plan + +1. Create `.jp/config/skill/rfd.toml` with the configuration described above. +2. Test with a few real RFD drafting sessions to validate that the system prompt + sections, tools, and attachment work as expected. Verify that the LLM + references RFD 001 conventions correctly, uses tools to research context, and + respects the collaborator role. +3. Adjust guidance based on experience. + +## References + +- [RFD 001: The JP RFD Process](001-jp-rfd-process.md) — the process this skill + teaches JP to follow. +- [RFD 002: Using LLMs in the JP Project](002-using-llms.md) — the guidelines on + LLM use that inform this skill's boundaries. +- [Skill: Read Files](../../.jp/config/skill/read-files.toml) — + extended by this skill for codebase exploration. +- [Skill: Project Discourse](../../.jp/config/skill/project-discourse.toml) + — extended by this skill for GitHub context. + +[RFD 001]: 001-jp-rfd-process.md +[RFD 002]: 002-using-llms.md diff --git a/justfile b/justfile index 229743a4..6908247c 100644 --- a/justfile +++ b/justfile @@ -99,6 +99,105 @@ profile-heap *ARGS: #!/usr/bin/env sh cargo run --profile profiling --features dhat -- "$@" +# Create a new RFD draft. STYLE is 'rfd' (design proposal) or 'adr' (decision record). +[group('rfd')] +rfd-draft STYLE +TITLE: + #!/usr/bin/env sh + set -eu + + style="{{STYLE}}" + + # Validate the style argument. + case "$style" in + rfd|adr) ;; + *) echo "Unknown style '$style'. Use 'rfd' or 'adr'." >&2; exit 1 ;; + esac + + # Find the next available RFD number. + last=$(ls docs/rfd/[0-9][0-9][0-9]-*.md 2>/dev/null \ + | sed 's|.*/||; s|-.*||' \ + | sort -n \ + | tail -1 \ + || echo "000") + + # Strip leading zeros to avoid octal interpretation in POSIX sh. + last=$(echo "$last" | sed 's/^0*//') + last=${last:-0} + next=$(printf "%03d" $((last + 1))) + + # Resolve the author from git config, falling back to $USER. + git_name=$(git config user.name 2>/dev/null || true) + git_email=$(git config user.email 2>/dev/null || true) + if [ -n "$git_name" ] && [ -n "$git_email" ]; then + author="${git_name} <${git_email}>" + elif [ -n "$git_name" ]; then + author="$git_name" + else + author="${USER:-unknown}" + fi + + # Build the filename slug from the title. + slug=$(echo "{{TITLE}}" | tr '[:upper:]' '[:lower:]' | tr ' ' '-' | tr -cd 'a-z0-9-') + file="docs/rfd/${next}-${slug}.md" + + # Copy the template and fill in metadata. + sed \ + -e "s/RFD NNN: TITLE/RFD ${next}: {{TITLE}}/" \ + -e "s/AUTHOR/${author}/" \ + -e "s/DATE/$(date +%Y-%m-%d)/" \ + "docs/rfd/000-${style}-template.md" > "$file" + + echo "Created $file" + +# Supersede RFD NNN with RFD MMM, updating both documents. +[group('rfd')] +rfd-supersede NNN MMM: + #!/usr/bin/env sh + set -eu + + old_n=$(echo "{{NNN}}" | sed 's/^0*//') + old_num=$(printf "%03d" "${old_n:-0}") + new_n=$(echo "{{MMM}}" | sed 's/^0*//') + new_num=$(printf "%03d" "${new_n:-0}") + old_file=$(ls docs/rfd/${old_num}-*.md 2>/dev/null | head -1) + new_file=$(ls docs/rfd/${new_num}-*.md 2>/dev/null | head -1) + if [ -z "$old_file" ]; then + echo "No RFD found with number ${old_num}." >&2; exit 1 + fi + if [ -z "$new_file" ]; then + echo "No RFD found with number ${new_num}." >&2; exit 1 + fi + + # Validate the old RFD can be superseded. + current=$(sed -n 's/^- \*\*Status\*\*: \([A-Za-z]*\).*/\1/p' "$old_file") + case "$current" in + Accepted|Implemented) ;; + *) + echo "Cannot supersede from '${current}'." >&2 + echo "Only Accepted or Implemented RFDs can be superseded." >&2 + exit 1 ;; + esac + + # Update old RFD: status -> Superseded, add/update "Superseded by" link. + awk -v new="RFD ${new_num}" ' + /^- \*\*Status\*\*:/ { print "- **Status**: Superseded"; next } + /^- \*\*Superseded by\*\*:/ { next } + /^- \*\*Date\*\*:/ { print; print "- **Superseded by**: " new; next } + { print } + ' "$old_file" > "${old_file}.tmp" + mv "${old_file}.tmp" "$old_file" + + # Update new RFD: add/update "Supersedes" link. + awk -v old="RFD ${old_num}" ' + /^- \*\*Supersedes\*\*:/ { next } + /^- \*\*Date\*\*:/ { print; print "- **Supersedes**: " old; next } + { print } + ' "$new_file" > "${new_file}.tmp" + mv "${new_file}.tmp" "$new_file" + + echo "${old_file}: Superseded by RFD ${new_num}" + echo "${new_file}: Supersedes RFD ${old_num}" + # Locally develop the documentation, with hot-reloading. [group('docs')] develop-docs: (_docs "dev" "--open")