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
154 changes: 154 additions & 0 deletions docs/promotions/P0003-reframe-before-trimming.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
---
uri: klappy://docs/promotions/P0003-reframe-before-trimming
title: "P0003: Reframe Before Trimming — When a Tool Surface Feels Bloated, Question the Frame"
audience: docs
exposure: nav
tier: 3
voice: neutral
stability: evolving
tags: ["promotions", "proposed", "mcp-server", "tool-surface", "refactoring", "vodka-architecture", "doing-less"]
promotion_status: proposed
---

# P0003: Reframe Before Trimming — When a Tool Surface Feels Bloated, Question the Frame

> When an MCP server's tool surface feels bloated, the bloat is usually in the frame the surface implies, not in the tool count. Reframe first; the trim follows mechanically.

## Observed Pattern

An MCP server's tool count drifts upward over time as features accrete. At some point the surface "feels wrong" — too many tools, too much overlap, too many edges to defend in PR review. The instinct is to ask "which tools can we cut?" and pick the weakest-justified ones. That move trims symptoms but preserves the conceptual model that produced the bloat.

The pattern observed across server projects is that the right move at this moment is structurally different: **suspect the frame the surface implies, not the count.** When the frame is wrong, the tool count collapses mechanically once the frame is corrected. When the frame is right and the count still feels high, the discomfort is usually about something else — vodka-boundary enforcement, async shape, or consumer-side wiring friction — and trimming will not address it.

- Affects: any MCP server going through scope review or v-bump refactoring
- Outcome without the move: smaller surface that still embodies the wrong model; conceptual debt persists; bloat returns at the next feature wave
- Outcome with the move: surface that fits the actual model; the trim is a side effect, not the goal

## Evidence

| Validation Session | Date | Outcome | Notes |
| --- | --- | --- | --- |
| `klappy/PTXprint-MCP` v1.0 → v1.1 | 2026-Q1 | Trimmed without reframing | 17 → 7 tools by cutting features; surface still modeled the server as a project filesystem |
| `klappy/PTXprint-MCP` v1.1 → v1.2 | 2026-Q2 | Reframed, then trimmed | Reframed PTXprint as a pure function `(config, sources, fonts) → PDF` with content-addressed cache; tool count collapsed to 3 mechanically |
| `klappy/agent-messaging-service` hosted /mcp planning | 2026-05-03 | Pre-emptive reframe applied | Same diagnostic move applied during planning; spec landed on 6 tools per `mcp-wrapper-conformance-for-conversational-ai` rather than drifting to 8+ via "while we're here" additions |

**Total observations**: 3 across 2 independent server projects
**Independent occurrences**: 2 distinct repositories
**Affected workflows**: MCP server v-bump refactoring, hosted protocol-endpoint planning

## Current Handling

- **Detection today**: each server project re-derives the discipline through some combination of `vodka-architecture` review, `kiss-simplicity-is-the-ceiling` pressure, and operator intuition during PR review
- **Guidance**: there is no named diagnostic move that surfaces "the count is a symptom; the frame is the cause" before the trim instinct fires
- **Closest existing canon**: `canon/principles/doing-less-enables-more.md` is the structural empirical claim about why thin substrates win, and its smell test catches additions ("while we're here, the substrate could just…"). It does not address the post-hoc case where the surface has already drifted and the bloat is observable

This promotion fills the operational gap: when an existing surface has already drifted, what is the diagnostic move?

## Proposed Promotion

### Target Document

`canon/methods/reframe-before-trimming.md` (new)

Method, not principle. The principle space is occupied by `doing-less-enables-more` (the structural claim) and `vodka-architecture` (the discipline). This document operationalizes a specific diagnostic move during refactoring.

### Section

Whole document; new file.

### Proposed Language

```markdown
---
uri: klappy://canon/methods/reframe-before-trimming
title: "Reframe Before Trimming — When a Tool Surface Feels Bloated, Question the Frame"
audience: canon
exposure: nav
tier: 2
voice: neutral
stability: evolving
tags: ["canon", "method", "refactoring", "tool-surface", "mcp-server", "vodka-architecture", "doing-less", "diagnosis"]
derives_from:
- klappy://canon/principles/doing-less-enables-more
- klappy://canon/principles/vodka-architecture
- klappy://canon/principles/kiss-simplicity-is-the-ceiling
complements:
- klappy://canon/methods/pivot-on-inversion
status: active
---

# Reframe Before Trimming

> When an MCP server's tool surface feels bloated, the bloat is usually in the frame the surface implies, not in the tool count. Reframe first; the trim follows mechanically.

## When This Method Applies

A surface feels bloated. The instinct is to cut tools. This method says: pause that instinct.

Specifically, this method applies when:

- An existing MCP server has accrued tools across multiple versions
- Reviewers describe the surface as "too many tools" or "feels overlapping"
- A refactor is being scoped that will trim the count

## The Method

1. **Do not ask "which tools can we cut?"**
2. **Ask "is the frame this surface implies actually correct?"** Write down what mental model a fresh consumer would build by reading the tool list cold. Compare it against what the server actually does in the world.
3. **If the frame is wrong, fix the frame.** Restate the server's job in one sentence that matches reality. The tool count usually collapses mechanically because tools justified only by the wrong frame stop being justified.
4. **If the frame is right and the tool count still feels high**, the discomfort is probably elsewhere — vodka-boundary leakage (`canon/principles/vodka-architecture.md`), async shape mismatch (`canon/principles/async-by-default-for-long-running-tools.md` if proposed), or consumer-side wiring friction. Diagnose that, not the count.

## Failure Mode — Trimming Without Reframing

Cutting tools without reframing produces a smaller surface that still embodies the wrong model. The tool count drops; the conceptual debt stays. Bloat returns at the next feature wave because the model's gravity pulls toward the same shape.

## Receipts

- **PTXprint-MCP v1.0 → v1.2.** v1.0 had 17 tools modeling the server as a project filesystem. v1.1 trimmed to 7 by cutting features but kept the filesystem frame. v1.2 reframed the server as a pure function `(config, sources, fonts) → PDF` with content-addressed cache. Tool count collapsed to 3 — `submit_typeset`, `get_job_status`, `cancel_job` — without functionality loss. The trim was a side effect of the reframe, not its goal.
- *(Receipt pattern: each future application adds one row — server, before-count, after-count, the reframe in one sentence. Dense, not narrative.)*

## Relationship to Adjacent Canon

This method is the operational complement to `canon/principles/doing-less-enables-more`. That principle is the structural empirical claim about why thin substrates win and catches NOT-ADOPTING-new-opinions through its smell test. This method addresses the post-hoc case: the substrate already drifted; the bloat is observable; what now?

`canon/methods/pivot-on-inversion` is adjacent but different — that method is about recovery when an iteration's gradient turns negative. This method is about diagnosis when a surface's tool count feels wrong. Pivot-on-inversion answers "should we keep going?"; reframe-before-trimming answers "what should we change first?"
```

### Rationale

The principle layer is occupied. `doing-less-enables-more` (2026-05-02) makes the structural claim; `vodka-architecture` defines the discipline; `kiss-simplicity-is-the-ceiling` constrains surface area at construction. None of them address the post-drift diagnostic move. This is a method-shaped gap, not a principle-shaped one — operationalizing a specific decision sequence during refactoring.

Placing this in `canon/methods/` rather than `canon/principles/` is deliberate. It sits next to `pivot-on-inversion` (also a method-shaped recovery procedure) and clearly relates to the principles via derives_from rather than competing with them.

## Risk Assessment

| Risk Level | Description |
| --- | --- |
| Low | Clarifies existing rule, no scope change |
| **Medium** | **Adds new method, may affect refactoring workflows** |
| High | Changes existing behavior, requires migration |

**Risk level**: Medium

**Mitigation**: The method is opt-in diagnostic guidance for refactoring, not a hard requirement. It does not block any workflow; it offers a sequencing rule for surface-level refactors. Adoption can be gradual — cited in PR descriptions when relevant, not enforced by gate.

## Status

`proposed`

## Review Notes

(To be filled during review)

- **Reviewer**:
- **Decision**:
- **Date**:
- **Notes**:

## Execution Record

(To be filled after acceptance)

- **Commit**:
- **Canon doc updated**: `canon/methods/reframe-before-trimming.md`
- **Backlink added**: Yes / No
151 changes: 151 additions & 0 deletions docs/promotions/P0004-docs-proxy-canon-as-tool.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
---
uri: klappy://docs/promotions/P0004-docs-proxy-canon-as-tool
title: "P0004: Docs Proxy — Canon-as-Tool So Consumers Wire One MCP, Not Two"
audience: docs
exposure: nav
tier: 3
voice: neutral
stability: evolving
tags: ["promotions", "proposed", "mcp-server", "docs-proxy", "canon", "vodka-architecture", "consumer-experience"]
promotion_status: proposed
---

# P0004: Docs Proxy — Canon-as-Tool So Consumers Wire One MCP, Not Two

> An MCP server that depends on a sibling canon repo for its domain knowledge SHOULD expose a `docs(query, ...)` tool that proxies the canon-server (oddkit), parameterized to its own repo. Consumers get both action tools and canon retrieval through one MCP wiring.

## Observed Pattern

Multiple MCP servers in this program depend on a sibling canon repo for governance and domain knowledge. Without intervention, every consumer of those servers must wire two MCPs to get the full surface: the action server, and the canon server (oddkit) configured with the action server's repo as `knowledge_base_url`.

The wire-two-MCPs tax is paid by every consumer, every time. Some consumers pay it; many do not. Those who do not pay it lose access to live canon at exactly the moment they need it most — mid-task, in-flow — and either abandon the canon-as-living-context value proposition or fall back to opening the canon repo's GitHub web UI.

The pattern observed is that one server-side decision — exposing a thin `docs` proxy tool that POSTs to the canon-server with the action server's repo URL — eliminates the tax for every current and future consumer.

- Affects: every consumer of every MCP server with a sibling canon repo
- Outcome without the tool: per-consumer onboarding friction; reduced canon-in-the-loop usage; canon drifts from living context to web-search-of-last-resort
- Outcome with the tool: one MCP wired, both surfaces accessible, canon stays in-flow

## Evidence

| Validation Session | Date | Outcome | Notes |
| --- | --- | --- | --- |
| `klappy/PTXprint-MCP` v1.0 D-004 | 2026-Q1 | "No retrieval in MCP server" — original decision | Server boundary kept thin; consumers expected to wire oddkit separately |
| `klappy/PTXprint-MCP` v1.2 session 13 | 2026-04-29 | Decision reversed; `docs(query, audience?, depth?)` added as 4th tool | Reversal rationale recorded in v1.2 spec: downstream agents (e.g., BT Servant) want one MCP, not two; vodka boundary preserved (the proxy holds zero domain semantics) |
| `klappy/agent-messaging-service` hosted /mcp planning | 2026-05-03 | Same gap re-identified | A Claude Desktop user wiring AMS-MCP today must also wire oddkit-MCP with `knowledge_base_url=agent-messaging-service` to get `ams://canon/...` retrieval. An `ams_docs` tool would absorb the tax once, server-side |

**Total observations**: 3 across 2 independent server projects
**Independent occurrences**: 2 distinct repositories, with the second project re-encountering the question without prior knowledge of the first project's resolution
**Affected workflows**: every consumer onboarding path for every oddkit-pattern MCP server in this program

## Current Handling

- **Detection today**: per-consumer friction is silent — operators notice it when they themselves try to onboard a new agent and discover they need to wire two MCPs
- **Workaround today**: consumers either accept the two-MCP tax or skip canon-in-flow entirely
- **Closest existing canon**: `canon/principles/consistency-same-pattern-every-time.md` says "the server behaves identically regardless of what knowledge base it serves" — that is the *same-server-many-knowledge-bases* axis. This promotion addresses the orthogonal axis: *many-servers-one-knowledge-base, single consumer wiring*. Both axes deserve coverage

## Proposed Promotion

### Target Document

`canon/patterns/docs-proxy-canon-as-tool.md` (new)

### Section

Whole document; new file.

### Proposed Language

```markdown
---
uri: klappy://canon/patterns/docs-proxy-canon-as-tool
title: "Docs Proxy — Canon-as-Tool So Consumers Wire One MCP"
audience: canon
exposure: nav
tier: 2
voice: neutral
stability: evolving
tags: ["canon", "pattern", "mcp-server", "docs-proxy", "consumer-experience", "vodka-architecture"]
derives_from:
- klappy://canon/principles/vodka-architecture
- klappy://canon/principles/consistency-same-pattern-every-time
- klappy://canon/principles/dry-canon-says-it-once
complements:
- klappy://canon/principles/doing-less-enables-more
status: active
---

# Docs Proxy — Canon-as-Tool

> An MCP server whose action surface depends on a sibling canon repo for domain semantics SHOULD expose a `docs(query, audience?, depth?)` tool that proxies the canon-server (oddkit), parameterized to its own repo. Consumers get both surfaces through one MCP wiring.

## The Pattern

The action MCP server adds one tool — typically named `docs` or `<server>_docs` — whose entire job is to forward queries to the canon-server with the action server's own repo URL pinned as the `knowledge_base_url` parameter.

- **Inputs**: `query` (required), `audience` (optional, server-defined enum), `depth` (optional `1|2|3` — snippet, full top doc, top + next two)
- **Returns**: `{ answer, sources[], deeper[], governance_source }`
- **Failure**: graceful degradation when the canon-server is unreachable — `{ answer: null, sources: [], governance_source: "minimal", error }` rather than a hard error that blocks consumer flow

## Vodka Check the Tool Must Pass

The proxy tool knows exactly two URLs: this server's canon repo and the canon-server's MCP endpoint. It holds zero domain semantics. It does not parse, rank, filter, score, or reframe results. It is a pinned forwarding layer.

If the proxy ever grows a domain-flavored taxonomy or a scoring tweak, that taxonomy moves into governance documents in the canon repo (which the canon-server retrieves through the same proxy), not into the tool's implementation. Domain logic in the proxy is a vodka-boundary leak.

## Why the Pattern Exists

Without the pattern, every consumer pays a wire-two-MCPs tax: one MCP for actions, a second MCP for canon retrieval, configured with the action server's repo as `knowledge_base_url`. Consumers who do not pay the tax lose canon-in-flow access at the moment they need it most. The pattern absorbs the tax once, server-side, for every present and future consumer.

This pattern is orthogonal to `canon/principles/consistency-same-pattern-every-time`, which covers the *same-server-many-knowledge-bases* axis. This pattern covers *many-servers-one-knowledge-base*. Both are real; both deserve canon coverage.

## Failure Mode

Without this pattern: per-consumer onboarding friction; canon drifts from living context to web-search-of-last-resort; the canon-as-living-context value proposition silently degrades because consumers never wire it.

With the pattern: one MCP wired, both surfaces accessible; canon stays in-flow as designed.

## Receipts

- **PTXprint-MCP v1.2 §3 `docs` tool.** Added in session 13 (2026-04-29), reversing v1.0's "no retrieval in MCP server" decision with explicit rationale: downstream agents like BT Servant want one MCP wiring. Vodka boundary preserved.
- *(Future receipts: each server adopting the pattern adds one row — server, tool name, date adopted, link to spec section.)*
```

### Rationale

The pattern's content has been independently re-derived in two server projects within ~6 weeks of each other. The cost of writing it once into canon is small; the cost of letting every future server's session re-derive it is paid every time. This is the `dry-canon-says-it-once` shape — say it once at canon, every future server reads it at preflight.

The placement under `canon/patterns/` rather than `canon/principles/` is deliberate. This is a concrete server-implementation pattern (specific tool shape, specific call mechanics), not a structural claim. `canon/patterns/` does not currently exist as a directory in the canon tree; this would establish it. If reviewers prefer to keep the directory namespace tighter, the document can land under `canon/methods/` instead with no content change.

## Risk Assessment

| Risk Level | Description |
| --- | --- |
| **Low** | **Clarifies existing rule, no scope change** |
| Medium | Adds new requirement, may affect workflows |
| High | Changes existing behavior, requires migration |

**Risk level**: Low

**Mitigation**: The pattern is opt-in for each server. Servers that do not depend on a sibling canon repo (none today, but hypothetical) need not adopt it. Adoption is per-server, gradual, additive.

## Status

`proposed`

## Review Notes

(To be filled during review)

- **Reviewer**:
- **Decision**:
- **Date**:
- **Notes**:

## Execution Record

(To be filled after acceptance)

- **Commit**:
- **Canon doc updated**: `canon/patterns/docs-proxy-canon-as-tool.md` (or `canon/methods/...` if directory placement is reconsidered)
- **Backlink added**: Yes / No
Loading
Loading