From 99743e9c151c8537cbbf1f98bb38f34ef3368453 Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 15 Oct 2026 09:29:09 -0700 Subject: [PATCH 1/4] refactor(pstack): cut marginal sections from four skills (#634) * refactor(pstack): cut marginal sections from four skills Remove sections that agents follow just as well without the text, in interrogate's lead-judgment reference, swarm, and the type-system and migrate-callers principles. Swarm keeps Phase A items 1 and 2, because Phase C still needs the race-rule sentence in item 2. * docs(pstack): drop 'refuse to lie to the compiler' from type-system summaries The body bullet that backed it is cut in this PR. Co-authored-by: lauren --------- Co-authored-by: Cursor Agent --- pstack/README.md | 2 +- .../interrogate/references/lead-judgment.md | 19 ------------------- .../SKILL.md | 8 -------- .../principle-type-system-discipline/SKILL.md | 7 +------ pstack/skills/swarm/SKILL.md | 5 ----- 5 files changed, 2 insertions(+), 39 deletions(-) diff --git a/pstack/README.md b/pstack/README.md index fcc9daa5d..4e8b8c2a6 100644 --- a/pstack/README.md +++ b/pstack/README.md @@ -224,7 +224,7 @@ twenty-four short skills, one principle each. `poteto-mode` indexes them inline | [build-the-lever](./skills/principle-build-the-lever/SKILL.md) | core | Apply to any non-trivial work, not just bulk work: edits, migrations, analyses, checks. Build the tool that does it or proves it (codemod, script, generator, or a skill your subagents follow) instead of working by hand. The tool is the artifact a reviewer can rerun. | | [model-the-domain](./skills/principle-model-the-domain/SKILL.md) | architecture | Encode the domain in a structure instead of scattered conditionals. | | [boundary-discipline](./skills/principle-boundary-discipline/SKILL.md) | architecture | Concentrate guards at system boundaries (CLI, config, network, external APIs); trust internal types and keep business logic in pure functions. | -| [type-system-discipline](./skills/principle-type-system-discipline/SKILL.md) | architecture | Make illegal states unrepresentable, brand semantic primitives, parse external data at boundaries, refuse to lie to the compiler, exhaust variants, derive from authoritative schemas. | +| [type-system-discipline](./skills/principle-type-system-discipline/SKILL.md) | architecture | Make illegal states unrepresentable, brand semantic primitives, parse external data at boundaries, exhaust variants, derive from authoritative schemas. | | [make-operations-idempotent](./skills/principle-make-operations-idempotent/SKILL.md) | architecture | Converge to the same end state regardless of partial prior runs. | | [migrate-callers-then-delete-legacy-apis](./skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md) | architecture | Migrate callers and delete the old API in the same wave instead of preserving compatibility layers. | | [separate-before-serializing-shared-state](./skills/principle-separate-before-serializing-shared-state/SKILL.md) | architecture | Eliminate the sharing first; serialize structurally only when one shared writer is a real invariant. | diff --git a/pstack/skills/interrogate/references/lead-judgment.md b/pstack/skills/interrogate/references/lead-judgment.md index 5ce526097..3b41346c9 100644 --- a/pstack/skills/interrogate/references/lead-judgment.md +++ b/pstack/skills/interrogate/references/lead-judgment.md @@ -1,18 +1,5 @@ # Lead Judgment Framework -You are the lead reviewer. The configured reviewers have produced their findings. Apply pragmatic engineering judgment. Don't aggregate. Filter, contextualize, and decide. - -## Why This Step Matters - -Adversarial reviewers are useful because they're aggressive. But aggression without context produces noise. The reviewers only saw a slice of the codebase and a one-paragraph intent statement. They don't know: - -- What was already tried and rejected -- What constraints exist outside the code (timeline, dependencies, migration plans) -- Which parts of the code are temporary scaffolding vs. permanent architecture -- What the next PR in the stack will address - -You have the full conversation context. Use it. - ## Filtering Principles ### Nitpick Gravity @@ -50,9 +37,3 @@ Don't dismiss findings just because they're uncomfortable. The whole point of ad - You read the finding and think "...yeah, actually" Be especially careful about dismissing security findings and correctness bugs. These deserve more scrutiny even when they come from a single model. - -## Verdict Calibration - -A good verdict is useful, not comprehensive. The user should be able to read the "Act On" section, fix those issues, and ship with confidence. If your "Act On" list has more than 5 items, you're probably not filtering hard enough. - -The "Dismissed" section is not busywork. It's a trust mechanism. Showing the user what you rejected and why lets them override your judgment where they disagree. This is more valuable than hiding the rejected findings. diff --git a/pstack/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md b/pstack/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md index 06c7cfd87..57ddd7b27 100644 --- a/pstack/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md +++ b/pstack/skills/principle-migrate-callers-then-delete-legacy-apis/SKILL.md @@ -6,17 +6,9 @@ disable-model-invocation: true # Migrate Callers Then Delete Legacy APIs -When we decide a new API is the right design, migrate callers and remove the old API in the same refactor wave instead of preserving compatibility layers. - -**Rule:** -- Do not keep legacy API paths only because internal callers still exist -- Inventory callers, migrate them, and delete the old API immediately -- Treat temporary adapters as exceptional and time-boxed, not default architecture - Update tests to assert the new contract, and delete tests that only protect pre-refactor implementation details **When this applies:** - No external users depend on backward compatibility - The project can absorb coordinated breaking changes - The new API is part of a simplification or refactor initiative - -Keeping both old and new APIs creates dual-path complexity, slows cleanup, and makes the codebase feel append-only. diff --git a/pstack/skills/principle-type-system-discipline/SKILL.md b/pstack/skills/principle-type-system-discipline/SKILL.md index 4321b83e2..9fa08b0b1 100644 --- a/pstack/skills/principle-type-system-discipline/SKILL.md +++ b/pstack/skills/principle-type-system-discipline/SKILL.md @@ -1,6 +1,6 @@ --- name: principle-type-system-discipline -description: "Apply when designing types, reviewing a function signature, or writing code in any statically-typed language. Make illegal states unrepresentable, brand semantic primitives, parse external data at boundaries, refuse to lie to the compiler, exhaust variants, derive from authoritative schemas." +description: "Apply when designing types, reviewing a function signature, or writing code in any statically-typed language. Make illegal states unrepresentable, brand semantic primitives, parse external data at boundaries, exhaust variants, derive from authoritative schemas." disable-model-invocation: true --- @@ -8,11 +8,6 @@ disable-model-invocation: true Make the compiler reject impossible states, mismatched primitives, and unhandled variants. Prefer defining errors and special cases out of existence over proliferating handlers. For TypeScript syntax, see the `typescript-best-practices` skill. -- **Make illegal states unrepresentable.** Model variants as sum types (discriminated unions, enums with payloads, sealed classes), not as a bag of optional fields where contradictory combinations compile. `{ completed: boolean; completedAt?: Date }` admits `completed: true` with no date. Derive the boolean from `completedAt`, or model `{ kind: 'open' } | { kind: 'done'; at: Date }`. If you can write a comment explaining when a combination of fields is valid, split it into a sum type. -- **Types are constructions, not restrictions.** Build the type up from the values you want instead of carving them out of a looser type with checks. A non-empty list is a head plus a rest. A valid time range is a start plus a duration. Choose the shape that cannot build the illegal value and expose the interface callers need on top. - **Brand semantic primitives.** `UserId` and `OrderId` are strings underneath but should not be interchangeable. Give each its own type, such as a branded intersection in TypeScript or a newtype elsewhere. Validate once at creation, trust the type downstream. If two arguments share a primitive type but mean different things, brand them. - **External data is untyped until parsed.** RPC payloads, JSON, IPC messages, CLI args, config files, environment variables, database rows. Have a parse function at every boundary that turns unstructured input into the typed model. The **boundary-discipline** principle skill says where to put validation. -- **Don't lie to the type system.** Casts, unsafe coercions, and assertion functions that bypass the compiler are latent runtime crashes. If the compiler can't prove a fact, prove it (validate, narrow, refine the model) or accept that the cast is a hazard. Trace each `any`, `as`, or `assertNotNull` to the boundary and validate there. -- **Exhaustive matching is the compiler's job.** A match on a sum type must fail compilation when a new variant is added without handling, so the compiler tells the next agent where to add a case. Use your language's idiom: a `never`-typed binding in TypeScript, an unannotated `match` in Rust, `-Wincomplete-patterns` in Haskell, sealed-class match exhaustiveness in Kotlin. - **Derive types from authoritative schemas.** When a protocol buffer, OpenAPI spec, GraphQL schema, database migration, design-token file, or another file owns a shape, derive from it instead of hand-rolling a parallel type. See the **encode-lessons-in-structure** principle skill. -- **Strengthen a type only where partiality appears.** A runtime assertion, null check, or "this should never happen" throw marks the place a type is too weak. Push that check up into the type. Then stop. The type system's job is to track the cases each use site must handle, not to describe the data as precisely as possible. Prefer total functions. `sum` of an empty list is 0, so it takes the plain list. `head` of an empty list has no answer, so it demands the non-empty one. If nothing would otherwise panic, keep the plain type. diff --git a/pstack/skills/swarm/SKILL.md b/pstack/skills/swarm/SKILL.md index ed99acb98..b0b1eb833 100644 --- a/pstack/skills/swarm/SKILL.md +++ b/pstack/skills/swarm/SKILL.md @@ -6,8 +6,6 @@ disable-model-invocation: true # Swarm -Fan out N parallel cloud workers. They may cover separate slices, race the same brief, or mix both. The parent waits, aggregates, and returns one report. - ## Start Open a todolist with one entry per phase before launching anything. @@ -21,7 +19,6 @@ Open a todolist with one entry per phase before launching anything. 1. State the done predicate and the artifact or report the swarm must return. 2. Choose the shape. Partition into slices, race N workers on identical briefs, or mix both. For a race or mixed shape, declare `first pass`, `rank all`, or `best-of` before spawning. -3. Set N from the user or derive it from the shape. N is total workers, not the cloud concurrency limit. 4. Pick the worker model from the `swarm workers` line in `~/.cursor/rules/pstack-models.mdc`. If the rule or that line is missing, use `grok-4.7-xhigh-fast`. For `auto` or `inherit-parent`, omit `model` so the workers run on the parent model. If the Task tool rejects a slug, use the default and say so. If it rejects the default, use the closest valid slug of the same family from its error message. For a model race, name each arm's model up front. Pick each subagent's reasoning level and fast or standard speed for the job, per the Subagents section of the **poteto-mode** skill. 5. Give each worker its own writable output when it writes. When workers verify or measure commits, each brief names the exact SHAs. A measurement brief also names the method (sample count, what one sample is, order). The worker records both in its result. @@ -39,8 +36,6 @@ If a worker drops out, proceed with N-1 and note it. Read the terminal results. Drop a result that does not record the SHAs and method its brief names, and respawn that worker once. After a second miss, record a gap. A gap does not count as a pass. For coverage, every required slice needs a result. For a race, apply the selection rule declared up front. Use first pass, rank all, or best-of. Do not paste raw worker dumps. -Keep a compact result table, one-line evidenced issues, and explicit gaps or dropouts. - ## Phase D: Report Return one consolidated in-chat report with the table, issue one-liners, gaps or dropouts, and the race rule when used. From 5c096d236a6ac98d9548affa711fa33c8bbf3ff4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 15 Oct 2026 20:37:24 +0000 Subject: [PATCH 2/4] feat(quickbooks-online): declare Intuit's HTTP MCP server The listing was gating-only: it carried no server definition, so an install produced no mcp_server row and native MCP had nothing to point at. Declare the hosted HTTP endpoint the way Square does, so the marketplace index exposes a type === "HTTP" server for the connector. Bumps the plugin to 1.1.0 and updates the README and CHANGELOG, which both documented the absent mcp.json as deliberate. Co-authored-by: Danny Jiang --- .../.cursor-plugin/plugin.json | 5 +++-- third_party/quickbooks-online/CHANGELOG.md | 5 +++++ third_party/quickbooks-online/README.md | 18 +++++++++++++----- third_party/quickbooks-online/mcp.json | 8 ++++++++ 4 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 third_party/quickbooks-online/mcp.json diff --git a/third_party/quickbooks-online/.cursor-plugin/plugin.json b/third_party/quickbooks-online/.cursor-plugin/plugin.json index 918a22232..7b15ea1f7 100644 --- a/third_party/quickbooks-online/.cursor-plugin/plugin.json +++ b/third_party/quickbooks-online/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "quickbooks-online", "displayName": "QuickBooks Online", - "version": "1.0.0", + "version": "1.1.0", "minClientVersions": { "cursor": "3.19.0" }, @@ -32,5 +32,6 @@ "accounting", "finance", "mcp" - ] + ], + "mcpServers": "./mcp.json" } diff --git a/third_party/quickbooks-online/CHANGELOG.md b/third_party/quickbooks-online/CHANGELOG.md index d51ce4231..684dd2b12 100644 --- a/third_party/quickbooks-online/CHANGELOG.md +++ b/third_party/quickbooks-online/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this plugin will be documented here. +## 1.1.0 + +- Added `mcp.json`: the plugin now declares Intuit's hosted HTTP MCP server at `https://mcp-e2e.quickbooks.intuit.com/mcp` instead of relying on a Cursor-side server definition. +- Auth is unchanged in shape — Cursor-managed OAuth against Intuit, authorized per company file — but it is now the native OAuth client, so existing installs have to reauthorize. + ## 1.0.0 — initial release - Added the `quickbooks-online` plugin, the opt-in for the QuickBooks Online MCP server that Cursor hosts and credentials. diff --git a/third_party/quickbooks-online/README.md b/third_party/quickbooks-online/README.md index b820becc2..1c204b5fc 100644 --- a/third_party/quickbooks-online/README.md +++ b/third_party/quickbooks-online/README.md @@ -1,6 +1,6 @@ # QuickBooks Online -Cursor plugin that connects agents to [QuickBooks Online](https://quickbooks.intuit.com) — Intuit's cloud accounting product — through a [Model Context Protocol](https://modelcontextprotocol.io/) server that Cursor hosts and credentials. +Cursor plugin that connects agents to [QuickBooks Online](https://quickbooks.intuit.com) — Intuit's cloud accounting product — through Intuit's remote [Model Context Protocol](https://modelcontextprotocol.io/) server, which Cursor credentials for you. Read a company file's accounting data: invoices, bills, expenses, payments, customers and vendors, the chart of accounts, journal entries, and the standard financial reports. @@ -14,11 +14,18 @@ Or run `/add-plugin quickbooks-online` in chat. ## MCP -This plugin ships no `mcp.json`, and that is deliberate. +```json +{ + "mcpServers": { + "quickbooks-online": { + "type": "http", + "url": "https://mcp-e2e.quickbooks.intuit.com/mcp" + } + } +} +``` -Every other connector in this repository either points at a vendor's hosted endpoint or runs a package locally over stdio, so it carries its own server definition. QuickBooks Online does not: Cursor runs the server, and the plugin exists only as the opt-in that turns it on for your account. Installing the plugin is what makes the server available; there is no command to run, no endpoint to reach, and no API key or client secret to paste. - -One consequence worth knowing: because the server is not declared here, you will not find it in a local `mcp.json` and you cannot point another MCP client at it. It is reachable from Cursor only. +The server is Intuit's, hosted by Intuit. Auth is OAuth against Intuit, which Cursor runs when the plugin connects — there is no command to run, and no API key or client secret to paste. ## Before you connect @@ -51,6 +58,7 @@ The server is the source of truth for tool names and schemas. - QuickBooks Online: https://quickbooks.intuit.com - Intuit Developer: https://developer.intuit.com - Model Context Protocol: https://modelcontextprotocol.io +- Server URL: https://mcp-e2e.quickbooks.intuit.com/mcp Logo is QuickBooks' official mark, from `quickbooks.intuit.com`. diff --git a/third_party/quickbooks-online/mcp.json b/third_party/quickbooks-online/mcp.json new file mode 100644 index 000000000..5fa7fdd8a --- /dev/null +++ b/third_party/quickbooks-online/mcp.json @@ -0,0 +1,8 @@ +{ + "mcpServers": { + "quickbooks-online": { + "type": "http", + "url": "https://mcp-e2e.quickbooks.intuit.com/mcp" + } + } +} From f506741cb55051574c5166102c32ffc26acb91e4 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Thu, 15 Oct 2026 20:42:37 +0000 Subject: [PATCH 3/4] docs(quickbooks-online): tighten the MCP section wording Co-authored-by: Danny Jiang --- third_party/quickbooks-online/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/third_party/quickbooks-online/README.md b/third_party/quickbooks-online/README.md index 1c204b5fc..7e149a177 100644 --- a/third_party/quickbooks-online/README.md +++ b/third_party/quickbooks-online/README.md @@ -25,7 +25,7 @@ Or run `/add-plugin quickbooks-online` in chat. } ``` -The server is Intuit's, hosted by Intuit. Auth is OAuth against Intuit, which Cursor runs when the plugin connects — there is no command to run, and no API key or client secret to paste. +Intuit hosts the server. Auth is OAuth against Intuit, which Cursor runs when the plugin connects — there is no command to run, and no API key or client secret to paste. ## Before you connect From ed4397c22a287ef61652055d550515e8851c7b2f Mon Sep 17 00:00:00 2001 From: Danny Jiang Date: Thu, 15 Oct 2026 20:18:14 -0700 Subject: [PATCH 4/4] Revert "quickbooks online native mcp" --- .../.cursor-plugin/plugin.json | 5 ++--- third_party/quickbooks-online/CHANGELOG.md | 5 ----- third_party/quickbooks-online/README.md | 18 +++++------------- third_party/quickbooks-online/mcp.json | 8 -------- 4 files changed, 7 insertions(+), 29 deletions(-) delete mode 100644 third_party/quickbooks-online/mcp.json diff --git a/third_party/quickbooks-online/.cursor-plugin/plugin.json b/third_party/quickbooks-online/.cursor-plugin/plugin.json index 7b15ea1f7..918a22232 100644 --- a/third_party/quickbooks-online/.cursor-plugin/plugin.json +++ b/third_party/quickbooks-online/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "quickbooks-online", "displayName": "QuickBooks Online", - "version": "1.1.0", + "version": "1.0.0", "minClientVersions": { "cursor": "3.19.0" }, @@ -32,6 +32,5 @@ "accounting", "finance", "mcp" - ], - "mcpServers": "./mcp.json" + ] } diff --git a/third_party/quickbooks-online/CHANGELOG.md b/third_party/quickbooks-online/CHANGELOG.md index 684dd2b12..d51ce4231 100644 --- a/third_party/quickbooks-online/CHANGELOG.md +++ b/third_party/quickbooks-online/CHANGELOG.md @@ -2,11 +2,6 @@ All notable changes to this plugin will be documented here. -## 1.1.0 - -- Added `mcp.json`: the plugin now declares Intuit's hosted HTTP MCP server at `https://mcp-e2e.quickbooks.intuit.com/mcp` instead of relying on a Cursor-side server definition. -- Auth is unchanged in shape — Cursor-managed OAuth against Intuit, authorized per company file — but it is now the native OAuth client, so existing installs have to reauthorize. - ## 1.0.0 — initial release - Added the `quickbooks-online` plugin, the opt-in for the QuickBooks Online MCP server that Cursor hosts and credentials. diff --git a/third_party/quickbooks-online/README.md b/third_party/quickbooks-online/README.md index 7e149a177..b820becc2 100644 --- a/third_party/quickbooks-online/README.md +++ b/third_party/quickbooks-online/README.md @@ -1,6 +1,6 @@ # QuickBooks Online -Cursor plugin that connects agents to [QuickBooks Online](https://quickbooks.intuit.com) — Intuit's cloud accounting product — through Intuit's remote [Model Context Protocol](https://modelcontextprotocol.io/) server, which Cursor credentials for you. +Cursor plugin that connects agents to [QuickBooks Online](https://quickbooks.intuit.com) — Intuit's cloud accounting product — through a [Model Context Protocol](https://modelcontextprotocol.io/) server that Cursor hosts and credentials. Read a company file's accounting data: invoices, bills, expenses, payments, customers and vendors, the chart of accounts, journal entries, and the standard financial reports. @@ -14,18 +14,11 @@ Or run `/add-plugin quickbooks-online` in chat. ## MCP -```json -{ - "mcpServers": { - "quickbooks-online": { - "type": "http", - "url": "https://mcp-e2e.quickbooks.intuit.com/mcp" - } - } -} -``` +This plugin ships no `mcp.json`, and that is deliberate. -Intuit hosts the server. Auth is OAuth against Intuit, which Cursor runs when the plugin connects — there is no command to run, and no API key or client secret to paste. +Every other connector in this repository either points at a vendor's hosted endpoint or runs a package locally over stdio, so it carries its own server definition. QuickBooks Online does not: Cursor runs the server, and the plugin exists only as the opt-in that turns it on for your account. Installing the plugin is what makes the server available; there is no command to run, no endpoint to reach, and no API key or client secret to paste. + +One consequence worth knowing: because the server is not declared here, you will not find it in a local `mcp.json` and you cannot point another MCP client at it. It is reachable from Cursor only. ## Before you connect @@ -58,7 +51,6 @@ The server is the source of truth for tool names and schemas. - QuickBooks Online: https://quickbooks.intuit.com - Intuit Developer: https://developer.intuit.com - Model Context Protocol: https://modelcontextprotocol.io -- Server URL: https://mcp-e2e.quickbooks.intuit.com/mcp Logo is QuickBooks' official mark, from `quickbooks.intuit.com`. diff --git a/third_party/quickbooks-online/mcp.json b/third_party/quickbooks-online/mcp.json deleted file mode 100644 index 5fa7fdd8a..000000000 --- a/third_party/quickbooks-online/mcp.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "mcpServers": { - "quickbooks-online": { - "type": "http", - "url": "https://mcp-e2e.quickbooks.intuit.com/mcp" - } - } -}