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
4 changes: 2 additions & 2 deletions ADOPTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ What you do **not** copy: HANDBOOK.md, the `methodology` domain, `examples/`, `t
## One-Command Install

```bash
curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.0/install.sh | bash -s -- <your-first-domain>
curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.1/install.sh | bash -s -- <your-first-domain>
```

`install.sh` performs the manual steps below, is idempotent, and never overwrites an existing file (it skips and tells you). It detects your package manager (npm, pnpm — workspaces included, yarn, bun) for the `yaml` dependency, and a dependency failure warns instead of aborting the install. Run it from the root of your repository; pass your first domain name as the argument. It refuses to run in a subdirectory of a repository that already runs Knowledge-Driven Engineering — a second catalog nothing reads — and names the directory to run it from. The argument only seeds a fresh install: on a repository that already has `knowledge/index.yaml` the installer creates no domain and points you to `npm run knowledge -- domain add <name>`. Installing, upgrading (`--upgrade`) and adding a domain are three separate actions. Offline installs work from a local clone: `KDE_SOURCE=/path/to/clone bash install.sh <domain>`. The script installs the release it belongs to (the tag in its own URL); to install another release, a branch or a commit, set `KDE_VERSION=main` (or `KDE_VERSION=v0.7.2`) in front of the command.
Expand All @@ -38,7 +38,7 @@ The installer classifies what it writes by owner (DR-011):
Every run compares the installed markers with the fetched version and warns when a framework-owned file differs — whether from a newer release upstream or a local edit. To refresh them:

```bash
curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.0/install.sh | bash -s -- --upgrade
curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.1/install.sh | bash -s -- --upgrade
```

`--upgrade` replaces framework-owned files that differ and reports each one (`upgrade tools/knowledge-check.mts (0.1.0 -> 0.2.0)`). A framework-owned file you edited locally is overwritten too, with an explicit `WARN` line naming it. Framework-owned files are not an extension point: if you need different validation behaviour, fork this repository and install from your fork; if the change would help everyone, contributions are welcome. Adopter-owned files are not touched by `--upgrade`. Templates are never overwritten; the installer prints a `note` line for each one that differs from the release, with the upstream URL, so you can decide whether to adopt the newer shape. Without branch protection and CODEOWNERS, human-only promotion is a procedural guarantee: the validator sees that an approver is recorded, not who typed it. New template files that a release adds (as `templates/model.md` and `templates/contract.md` were) arrive on a plain run, because the installer adds any file that does not exist yet.
Expand Down
2 changes: 1 addition & 1 deletion HANDBOOK.md
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ Operational learning can update a spec, add a playbook, or trigger a new RFC. Us
Every transition above is one command (DR-013); each ends by running the validator and refreshing the domain manifests, and the transitions roll back if they would leave an error behind.

- `npm run knowledge -- new <type> <domain> "<title>" [--by agent] [--author <name>]` — copy the template, allocate the next id in the domain's own prefix, fill the metadata.
- `npm run knowledge -- promote <ID> --by <human> [--topic <name>]` — set the active status, record the approver, index a decision under its topic. Refused, with the validator's reason, when the document is not ready.
- `npm run knowledge -- promote <ID> --by <human> [--topic <name>]` — set the active status, record the approver, and name where the document stands: a decision is indexed under its topic, and any document that becomes `current` is declared under that name in its domain's `current:` so `CONTEXT.md` lists it. Without `--topic` a current document is promoted but not declared, and the command says so. Refused, with the validator's reason, when the document is not ready.
- `npm run knowledge -- supersede <OLD-ID> --by <NEW-ID> [--approved-by <human>]` — link both records, re-point or retire the topic, promote a draft replacement, list the documents that depend on the old one.
- `npm run knowledge -- domain add <name> --description "<text>" [--code-paths a/ b/]` — directory, README, empty decision index, catalog entry, manifest.
- `npm run knowledge -- backfill <domain>` — start or resume a brownfield backfill session (DR-018): scaffold the session file and the draft baseline decision, or report what is approved, rejected, and still pending.
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Requires Node 22.6+ (only for the tools; your project can be any stack).
**Existing codebase** — from the repo root:

```bash
curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.0/install.sh | bash -s -- orders
curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.1/install.sh | bash -s -- orders
npm run knowledge -- backfill orders
```

Expand Down
4 changes: 2 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# Installs Knowledge-Driven Engineering scaffolding into the current repository.
#
# Usage, from the root of your repository:
# curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.0/install.sh | bash -s -- <first-domain>
# curl -fsSL https://raw.githubusercontent.com/emafriedrich/knowledge-driven-engineering/v0.8.1/install.sh | bash -s -- <first-domain>
#
# From a local clone (offline / development):
# KDE_SOURCE=/path/to/knowledge-driven-engineering bash install.sh <first-domain>
Expand Down Expand Up @@ -37,7 +37,7 @@ done
REPO_URL="https://github.com/emafriedrich/knowledge-driven-engineering"
# Release this copy of the installer belongs to; bumped with package.json on
# every release so a curl of the script installs the matching tools.
DEFAULT_REF="v0.8.0"
DEFAULT_REF="v0.8.1"
REF="${KDE_VERSION:-${KDE_REF:-$DEFAULT_REF}}"

say() { printf '%s\n' "$*"; }
Expand Down
6 changes: 5 additions & 1 deletion knowledge/methodology/CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Knowledge-Driven Engineering methodology rules, examples, and agent guidance.
| --- | --- | --- | --- |
| product_vision | KDE-PV-001 | Knowledge-Driven Engineering product vision | 2026-08-30 |
| lifecycle_flow | KDE-FLOW-001 | Knowledge evolution lifecycle | 2026-08-30 |
| artifact_spec | KDE-SPEC-001 | Knowledge artifact and metadata rules | 2026-09-21 |
| artifact_spec | KDE-SPEC-001 | Knowledge artifact and metadata rules | 2026-09-30 |
| agent_context | KDE-PROMPT-001 | Coding agent context template | 2026-09-30 |
| signals_playbook | KDE-PLAYBOOK-001 | Drafting knowledge from external signals | 2026-09-09 |

Expand Down Expand Up @@ -42,8 +42,12 @@ Knowledge-Driven Engineering methodology rules, examples, and agent guidance.

## Pending — NOT current truth, do not obey

- `DR-020` (draft, agent-drafted): promote --topic names the catalog anchor of a current document; the validator warns on an unanchored current spec
- `KDE-RFC-010` (draft, agent-drafted): Distribute framework tooling as an npm package
- `KDE-RFC-015` (draft, agent-drafted): Re-anchor agents in-session: the hook returns the domain manifest on code edits
- `KDE-RFC-016` (draft, agent-drafted): External signals leave a mechanical trace: a draft must cite the ticket the work came from
- `KDE-RFC-017` (draft, agent-drafted): Is the task artifact worth keeping when field use never wrote one
- `KDE-RFC-018` (draft, agent-drafted): Decisions that span repositories: where a cross-service rule lives

## Rules

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
---
id: DR-020
title: "promote --topic names the catalog anchor of a current document; the validator warns on an unanchored current spec"
status: draft
created: 2026-09-30
updated: 2026-09-30
drafted_by: agent
approved_by: []
scope: [methodology]
tags: [decision]
depends_on: []
related: [DR-007, DR-009, DR-013, DR-019, KDE-SPEC-001]
supersedes: []
superseded_by: []
---

# DR-020: promote --topic names the catalog anchor of a current document; the validator warns on an unanchored current spec

## Context

A domain's `CONTEXT.md` lists its current truth from the `current:` map of the domain entry in `knowledge/index.yaml` (DR-009, KDE-SPEC-001). Promoting a spec, flow, model or any other document to `current` only changed the document's own `status`, so nothing put it in that map. The marketplace example shipped two `status: current` specs while its manifest read "Current truth: None yet", and an adopter promoting a spec today hits the same gap: the document says it is current, the manifest an agent reads does not. Deriving the anchors from status instead was rejected in DR-009, because a domain can hold two current specs for one role and the catalog is where a human says which one stands.

Decision indexes already solve the same problem for Decision Records: `promote --topic <name>` writes the topic in the same operation as the status change.

## Decision

1. **`promote <ID> --by <human> --topic <name>` declares the document.** For every type whose promoted status is `current` (spec, flow, ia, design-system, model, contract, playbook, prompt), `--topic` writes `<name>: <ID>` under `current:` in the domain's entry of its catalog, in the same operation that sets the status, and the domain manifest is regenerated. The name is the place the document occupies in the domain, in one or two words (`availability`, `product_vision`). It is the same concept as a decision topic and uses the same flag.
2. **A name held by a different document is refused.** The error names the current holder. Replacing an anchor is done by hand until supersession covers documents other than Decision Records.
3. **Without `--topic`, promotion still succeeds** and says the document is not declared in the catalog, so `CONTEXT.md` will not list it. Some current documents are deliberately not anchors.
4. **Re-running with `--topic` on a document that is already current anchors it** without touching the document, the way a promoted Decision Record missing from its index is indexed. This is how an existing project repairs a spec it promoted earlier.
5. **`--topic` on a type without a current status is refused** (RFC, task), instead of being silently ignored as before.
6. **The validator warns, never fails,** when a `current` spec is not listed under `current:` of its domain. Only specs are checked: the precedence rule names the current spec, and warning on every playbook or flow would bury the signal.

Anchoring changes what agents treat as truth, so it stays a human act under `--by` (DR-007).

## Consequences

- Promoting a spec with `--topic` leaves the catalog, the document and the manifest consistent in one command, and `knowledge:context --check` passes.
- A project upgrading the tools may see new warnings for current specs it never anchored; `promote <ID> --by <human> --topic <name>` clears each one.
- Affected artifacts: `tools/knowledge.mts`, `tools/knowledge-check.mts`, KDE-SPEC-001 (Domain Catalog Fields), HANDBOOK.
- Not covered: supersession between documents other than Decision Records, and shorter default topics for Decision Records. Both stay separate questions.

## Supersession

None.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
---
id: KDE-RFC-016
title: "External signals leave a mechanical trace: a draft must cite the ticket the work came from"
status: draft
created: 2026-09-30
updated: 2026-09-30
drafted_by: agent
approved_by: []
motivated_by: Maintainer question (2026-09-30) — whether turning a ticket into a Decision Record or RFC, and catching a contradiction between the ticket and current truth, is deterministic; it is not, it rests on the agent following KDE-PLAYBOOK-001 and DR-019, and a missed ticket leaves no trace
scope: [methodology]
tags: [rfc, agents, integration]
depends_on: []
related: [DR-008, DR-014, DR-019, KDE-PLAYBOOK-001, KDE-RFC-015]
---

# RFC: External signals leave a mechanical trace: a draft must cite the ticket the work came from

## Summary

When a pull request names a ticket from a tracker the domain declares, and it changes code under that domain's `code_paths`, the drift gate requires some knowledge document to cite that ticket, or the pull request to say why none is needed. The agent's judgment (which artifact, whether the ticket contradicts current truth) stays judgment; what becomes mechanical is that a ticket cannot drive code without leaving a trace in the knowledge.

## Problem

KDE-PLAYBOOK-001 tells an agent what to do with a ticket: read the domain first, quote rather than obey, and draft one Decision Record, RFC or task per cluster of signals. DR-019 tells it to draft an RFC and stop when the request is ambiguous. Both are prose. An agent that reads a ticket, sees nothing new in it, and goes straight to code leaves nothing behind: the decision someone took in a meeting and wrote in the ticket lives only in the tracker, and the code implements it without citing it. This is the most common way decisions taken outside the repository drift away from it.

Two parts of the problem cannot be mechanized and this RFC does not try: deciding which artifact fits, and noticing that a ticket contradicts a current spec. Both need reading. What can be checked is the trace.

## Proposal

- **The trigger is the pull request, not the conversation.** The gate already reads the pull request body (DR-008, DR-015). If the body or the branch's commit messages contain a key of a tracker the catalog declares for a touched domain (`trackers: { jira: PD }` makes `PD-123` a key), the pull request names a ticket.
- **The obligation.** For each ticket named, some document in the domain must cite it, in `motivated_by` or `external_ref`, either already in the repository or added in the pull request. Otherwise the gate fails and names the ticket.
- **The escape, visible like the others.** `no-knowledge: PD-123 <reason>` in the body satisfies it for that ticket ("typo fix", "the rule is already DR-023"). It is printed in the CI log, the same as `no-behavior-change`.
- **No tracker API.** The gate never calls Jira; it reads text it already has. External systems stay signals (DR-014), and the check works offline.
- **Only for declared trackers.** A domain with no `trackers:` entry is untouched, so the check costs nothing to teams that don't use one.

## Alternatives

- **Status quo: the playbook alone.** Works when the agent follows it; leaves no trace when it doesn't, and nobody notices.
- **A hook that detects tracker links in the user's prompt.** Some harnesses offer a prompt hook that could see a pasted link and remind the agent of the playbook. Worth having as a nudge, but not every harness has one, and a conversation is not something the repository or CI can check later.
- **Require a Decision Record for every ticket.** Most tickets are work justified by existing truth; this would flood the repository with records that only restate the ticket.
- **Detect contradictions mechanically**, by comparing the ticket to the spec. Needs reading the ticket and judging meaning; not deterministic, and it would call the tracker.

## Open Questions

- **Where tickets are named.** Pull request body only, or commit messages and branch name too? Branch names like `PD-123-fix-search` are common and would catch more; they would also catch tickets the author never meant to cite.
- **Is an existing citation enough?** A ticket already cited by an old record satisfies the check even if the new code does something else. Accept it (the trace exists) or require the citing document to be touched in the pull request?
- **Does a draft count?** A draft RFC citing the ticket is a trace, and implementing against it is already governed by DR-015. Propose yes.
- **Trackers without keys.** Linear and Jira have keys; Notion or a Confluence page has a URL. Match declared URL prefixes too, or keys only for a first version?

## Outcome

<!-- Fill after review: accepted, rejected, or deferred, with links to resulting decisions/specs. -->
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
---
id: KDE-RFC-017
title: Is the task artifact worth keeping when field use never wrote one
status: draft
created: 2026-09-30
updated: 2026-09-30
drafted_by: agent
approved_by: []
motivated_by: Field use (2026-09-30) — the first production adoption has no task documents in any domain, and neither example ships one; the only task artifact in the repository is the template, while DR-014 already lets a tracker own task status
scope: [methodology]
tags: [rfc, lifecycle]
depends_on: []
related: [DR-013, DR-014, DR-016, KDE-PLAYBOOK-001, KDE-RFC-015]
---

# RFC: Is the task artifact worth keeping when field use never wrote one

## Summary

Decide whether the task artifact stays a first-class type, becomes only a bridge to a tracker, or is repositioned as a plan an agent keeps across sessions. Field use never wrote one, and the method works without them.

## Problem

The artifact set has a task type (`templates/task.md`, `knowledge new task`, `knowledge done`, the `done` status, DR-013, DR-016). In field use no one created a task: the adopter works from Decision Records and specs, and work itself lives elsewhere. Neither example ships one. A type nobody uses still costs: documentation, a template, a status only it may hold, validator rules, and a question every new adopter asks ("do I write tasks too?") that the method answers with "only if you want to".

The case for tasks is real but narrow. A team without a tracker has nowhere else to put work. And a spec large enough to take several sessions needs a plan that survives the end of a session, which is where fast drift happens (KDE-RFC-015). Neither case is served by today's framing, which presents tasks as the default place for implementation work.

## Proposal

No choice is made here; the options are laid out for review.

- **A. Keep as is.** Tasks remain a first-class type. Document plainly that a team with a tracker does not need them.
- **B. Tracker bridge only.** A task document exists to link a ticket (`external_ref`) to the knowledge that justifies it, and nothing else. `knowledge new task` requires `external_ref`. Teams without a tracker put work in the tool they already use.
- **C. Session plan.** Reposition tasks as the plan an agent writes when a spec needs more than one session: bounded steps, each citing the spec rule it serves, closed with `knowledge done`. Retrieval (CONTEXT.md) lists open tasks so the next session resumes from the plan instead of from memory.
- **D. Remove the type.** Keep `external_ref` on Decision Records and specs for linking tickets, drop the template, the command and the `done` status, with a migration note for anyone who wrote tasks.

## Alternatives

Covered by the options above. Waiting for more field evidence is itself an option, and a cheap one: nothing breaks while the question is open.

## Open Questions

- Is one adoption without tasks evidence enough to change the artifact set, or does it only justify changing how tasks are presented?
- If C: does the plan belong in the repository at all, or is it scratch state for the harness that should not be committed?
- If D: DR-014 names tasks as the one thing a tracker may own. What replaces that exception, or does it disappear with the type?
- If B or D: what happens to the `done` status and `knowledge done`, which exist only for tasks?

## Outcome

<!-- Fill after review: accepted, rejected, or deferred, with links to resulting decisions/specs. -->
Loading
Loading