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
2 changes: 1 addition & 1 deletion .changeset/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Hello and welcome! This folder is managed by `@changesets/cli`. Full docs: https

## Workflow for this repo

The ten publishable packages — `acture`, `@acture/state-zustand`, `@acture/state-redux`, `@acture/palette-react`, `@acture/hotkeys`, `@acture/forms-autoform`, `@acture/forms-rjsf`, `@acture/mcp`, `@acture/ai-vercel`, `@acture/migration` — share a **fixed** version (see `config.json`). When any of them changes, all ten get a matching bump.
The ten publishable packages — `acture`, `acture-state-zustand`, `acture-state-redux`, `acture-palette-react`, `acture-hotkeys`, `acture-forms-autoform`, `acture-forms-rjsf`, `acture-mcp`, `acture-ai-vercel`, `acture-migration` — share a **fixed** version (see `config.json`). When any of them changes, all ten get a matching bump.

Add a changeset to any non-trivial PR:

Expand Down
26 changes: 13 additions & 13 deletions .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@
"fixed": [
[
"acture",
"@acture/state-zustand",
"@acture/state-redux",
"@acture/palette-react",
"@acture/hotkeys",
"@acture/forms-autoform",
"@acture/forms-rjsf",
"@acture/mcp",
"@acture/ai-vercel",
"@acture/migration"
"acture-state-zustand",
"acture-state-redux",
"acture-palette-react",
"acture-hotkeys",
"acture-forms-autoform",
"acture-forms-rjsf",
"acture-mcp",
"acture-ai-vercel",
"acture-migration"
]
],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": [
"@acture/example-graph-editor",
"@acture/example-drop-in",
"@acture/example-zustand-wrap-before",
"@acture/example-zustand-wrap-after"
"acture-example-graph-editor",
"acture-example-drop-in",
"acture-example-zustand-wrap-before",
"acture-example-zustand-wrap-after"
]
}
35 changes: 22 additions & 13 deletions .claude/skills/acture-architecture-primer/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
name: acture-architecture-primer
description: Load the conceptual model of acture's command-dispatch architecture. Use this skill at the start of ANY non-trivial task in the acture repository — it covers the three primitives (state model, command registry, schema bridge), the eight consumer surfaces, the three positioning paths (greenfield-pure, strangler-fig, footprint-minimizer), and the rule of three. Triggers on phrases like "what is acture", "how does the architecture work", "the three primitives", "the consumer surfaces", or when starting a new phase. Do NOT use this for narrow API/typing questions — load `acture-command-record-shape` or another targeted skill instead.
description: Load the conceptual model of acture's command-dispatch architecture. Use this skill at the start of ANY non-trivial task in the acture repository — it covers the three primitives (state model, command registry, schema bridge), the eight consumer surfaces, acture's dev-tool-first positioning and its two flexibility dimensions, and the rule of three. Triggers on phrases like "what is acture", "how does the architecture work", "the three primitives", "the consumer surfaces", or when starting a new phase. Do NOT use this for narrow API/typing questions — load `acture-command-record-shape` or another targeted skill instead.
---

# acture architecture primer
Expand All @@ -11,7 +11,7 @@ You are working on **acture**, a TypeScript library implementing the command-dis

Acture is built on three interlocking primitives. They are not optional layers — they are the minimal framework.

1. **State model** — a typed schema over application state. Defines *what exists*. Acture is agnostic about the state library; an adapter interface (`StateAdapter<S>`) lets zustand, Redux Toolkit, Jotai, etc. plug in cleanly. Reference adapters: `@acture/state-zustand` (Phase 1) and `@acture/state-redux` (Phase 2).
1. **State model** — a typed schema over application state. Defines *what exists*. Acture is agnostic about the state library; an adapter interface (`StateAdapter<S>`) lets zustand, Redux Toolkit, Jotai, etc. plug in cleanly. Reference adapters: `acture-state-zustand` (Phase 1) and `acture-state-redux` (Phase 2).

2. **Command registry** — a centralized map from a string `id` to a `CommandRecord`. Defines *what can be done*. Every user-facing operation flows through `registry.dispatch(id, params, ctx?)`. Carries the rest of the metadata: title, description, parameters, when-clauses, keybindings, tier marker, atomic-or-handoff flag.

Expand All @@ -21,22 +21,27 @@ Acture is built on three interlocking primitives. They are not optional layers

A single `CommandRecord` simultaneously serves:

1. **Command palette** + **keyboard shortcuts** (`@acture/palette-react` + `@acture/hotkeys`)
2. **AI tool calling** (`@acture/ai-vercel`) — schema → JSON Schema for LLM function calling
3. **MCP server** (`@acture/mcp`) — `{name, description, inputSchema}` tool emission
1. **Command palette** + **keyboard shortcuts** (`acture-palette-react` + `acture-hotkeys`)
2. **AI tool calling** (`acture-ai-vercel`) — schema → JSON Schema for LLM function calling
3. **MCP server** (`acture-mcp`) — `{name, description, inputSchema}` tool emission
4. **End-to-end testing** — same `dispatch(id, params)` used by tests at unit/component/E2E levels
5. **Telemetry** (post-v1) — middleware logging every dispatch
6. **Undo/redo** (post-v1) — `Result<R>` reserves `patches?` and `effects?`
7. **Macros** (post-v1) — record/replay of `{commandId, params}` pairs
8. **Extensions/plugins** — third-party additions via the registry API

## The three positioning paths
## Positioning: acture is a development tool first

Same core. Different documentation and different adapter package combinations.
**Read `docs/positioning.md` — it is canonical and governs every user-facing word.** The headline:

- **Greenfield-pure** — `acture` + `@acture/state-zustand` + consumer adapters. No migration package.
- **Strangler-fig migration** — `acture` + `@acture/migration` + existing state lib's adapter. Uses `wrapMutation`, `actureMiddleware`, `chooseImplementation`, `shadowCompare` (per research-4 §A.6). Graduates eventually.
- **Footprint-minimizer drop-in** — `acture` + `@acture/palette-react` + `@acture/mcp` + minimal `wrapMutation`. No deeper migration intent.
> acture is a place developers (human or agent) go to get AI-agentic help building, migrating to, and maintaining a command-dispatch architecture. It is delivered primarily as **skills, patterns, and codemods**; the `acture-*` npm packages are an **optional accelerator**, not the product. A developer must be able to use acture purely as a development tool with **no `acture-*` dependency added to their project** — unless they explicitly choose to.

Every engagement sits on **two independent dimensions** — keep both open, never collapse one into a default:

1. **Core vs strangler-fig** — is command dispatch designed in, or wrapped into an existing codebase incrementally? (The conceptual paper's three "positioning paths" — greenfield-pure, footprint-minimizer, strangler-fig — collapse onto this axis: the first two are *core*, the third is *strangler-fig*.)
2. **Agent-written vs package-reuse** — does the agent write the integration into the project (zero acture dependency, maximum adaptability), or install an `acture-*` package (less code to own, tested, at the cost of a dependency)? Decided **per consumer**, not per project.

**Standing rule:** whenever your task touches a consumer surface or a consumer-specific `acture-*` package, also load the **`acture-consumer-integration`** skill. It operationalises the positioning above; this primer only states it.

## The rule of three

Expand Down Expand Up @@ -69,8 +74,11 @@ From the central paper §6:
## Where the canonical sources live

- **Conceptual:** `docs/command_dispatch_journal_article.md`
- **Plan:** `docs/v1_plan.md`
- **Execution:** `docs/implementation_plan.md`
- **Positioning:** `docs/positioning.md` — canonical; governs every user-facing word (dev-tool-first, the two dimensions)
- **Forward plan + status:** `docs/roadmap.md` — what's done, what's next, what's deferred
- **Immediate handoff:** `docs/next_session.md`
- **v1 plan (historical):** `docs/v1_plan.md`
- **Execution (historical):** `docs/implementation_plan.md`
- **Don'ts:** `docs/redesign_takeaways.md` §3 (also the `acture-hard-donts` skill)
- **Research:** `docs/research/acture_research_{1..5} ...md` — load only what's relevant to your task

Expand All @@ -80,6 +88,7 @@ You should now be able to answer for any acture task:
- Which primitive does this touch?
- Which consumer surfaces does this affect?
- Does this risk one of the four named anti-patterns?
- Is this in scope for the current phase (per `implementation_plan.md`), or post-v1?
- Does this honour the dev-tool-first positioning — could a developer do this with zero `acture-*` dependency?
- If it touches a consumer surface, did you also load `acture-consumer-integration`?

If you can't answer those, re-read the relevant section.
8 changes: 4 additions & 4 deletions .claude/skills/acture-command-record-shape/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ type CommandRecord<P = unknown, R = unknown> = {

/** Tier (research-5). Authoritative source is the JSDoc tag on the defineCommand
* call site (@stable / @experimental / @internal / @deprecated). The build step
* (@acture/build-tier) mirrors the tag into this field. Authors normally do NOT
* (acture-build-tier) mirrors the tag into this field. Authors normally do NOT
* write this field manually — they write the JSDoc tag. */
tier?: "stable" | "experimental" | "internal" | "deprecated";

/** Free-text reason injected by the build step from @deprecated <reason>.
* Adapter packages (@acture/mcp, @acture/ai-vercel) prepend
* `[DEPRECATED — <reason>]` to the description; @acture/devtools surfaces
* Adapter packages (acture-mcp, acture-ai-vercel) prepend
* `[DEPRECATED — <reason>]` to the description; acture-devtools surfaces
* it in the inspector. Added in v1.0 (Phase 4) under the rule of three. */
deprecationReason?: string;

Expand Down Expand Up @@ -98,7 +98,7 @@ type Result<R> =
| { ok: false; error: { code: string; message: string; details?: unknown } };
```

The `patches?` and `effects?` fields are **reserved hooks** for `@acture/undo` (post-v1). v1 core ignores them. They exist so adding undo later is non-breaking.
The `patches?` and `effects?` fields are **reserved hooks** for `acture-undo` (post-v1). v1 core ignores them. They exist so adding undo later is non-breaking.

## Fields that are deliberately NOT on this record

Expand Down
88 changes: 88 additions & 0 deletions .claude/skills/acture-consumer-integration/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
name: acture-consumer-integration
description: The foundational pattern for building a command-dispatch CONSUMER in a target project — a command palette, keyboard shortcuts, AI tool calling, an MCP endpoint, e2e testing, macros, telemetry, undo. Load this whenever you are adding a consumer surface to a user's app, OR whenever you are working on a consumer-specific acture-* package (acture-palette-react, acture-hotkeys, acture-mcp, acture-ai-vercel, acture-e2e-playwright, …). It encodes acture's dev-tool-first positioning: the agent-written path is always viable, acture packages are an optional opt-in accelerator, and tool-library choices belong to the user. Triggers on "add a command palette", "add hotkeys", "wire up MCP", "expose commands to an AI", "set up e2e testing", "build a consumer", "which acture package should I use", "do I need to install acture".
---

# acture consumer integration — the foundational pattern

A **consumer** is anything that invokes commands from the registry: a command palette, keyboard shortcuts, AI tool calling, an MCP server, e2e tests, macros, telemetry, undo/redo, third-party extensions. Each is a *projection* of the same `CommandRecord` set.

This skill is the pattern every consumer-specific skill builds on. Load it before adding any consumer to a user's project, and before working on any consumer-specific `acture-*` package. The canonical positioning it enforces lives in `docs/positioning.md` — read that if anything here is unclear.

## The one rule you cannot break

> The user must be able to get a working consumer **without adding any `acture-*` dependency to their project**, unless they explicitly choose to.

If you find yourself reaching for `npm install acture-<something>` as the *default* move, stop. That is one of two options, and not the default one.

## Two dimensions — always keep both open

Before writing anything, locate the task on both axes (see `docs/positioning.md` §3):

1. **Core vs strangler-fig** — is command dispatch being designed in, or wrapped into an existing codebase incrementally? (If strangler-fig, also load the `migration-*` skills.)
2. **Agent-written vs package-reuse** — will you hand-write this consumer following acture's patterns, or install an acture package that implements it?

Dimension 2 is decided **per consumer**, not per project. Hand-write the palette, reuse `acture-mcp`, skip a state adapter — all in the same project — is normal.

## The decision procedure

For each consumer the user wants:

### Step 1 — Surface the choice to the user

Do not silently pick. Present the two paths with their real trade-offs:

- **Agent-written** — you write the integration into their codebase. They own every line, zero acture dependency, maximum adaptability to their stack. Cost: more code in their repo, and they maintain it.
- **Package-reuse** — install the relevant `acture-*` package. Less code to own, tested behaviour, faster. Cost: a dependency to track, a surface they don't control.

If the user has a stated preference (in `CLAUDE.md`, in conversation, in the migration plan), follow it. Otherwise ask.

### Step 2 — Identify the tool-library dependency (this one is usually unavoidable)

Almost every consumer rests on *some* third-party library:

| Consumer | Typical tool libraries | acture's per-tool package |
| ------------------- | ----------------------------------------------- | ------------------------- |
| Command palette | cmdk, kbar, custom | `acture-palette-react` (cmdk) |
| Keyboard shortcuts | tinykeys, react-hotkeys-hook, custom | `acture-hotkeys` (tinykeys) |
| AI tool calling | Vercel AI SDK, Anthropic SDK, OpenAI SDK | `acture-ai-vercel` (Vercel AI SDK) |
| MCP server | `@modelcontextprotocol/sdk` | `acture-mcp` |
| Parameter forms | react-hook-form + Zod, rjsf, custom | `acture-forms-autoform`, `acture-forms-rjsf` |
| e2e testing | Playwright, Cypress, custom | `acture-e2e-playwright` *(planned)* |

**This dependency belongs to the user's consumer code, and the choice of tool is theirs.** acture does not mandate cmdk or Playwright or the Vercel SDK. The per-tool `acture-*` packages each bundle *one* known-good integration with *one* tool — useful if the user already chose that tool, irrelevant if they chose another. Name the realistic options; respect the user's pick; never imply acture's choice is the only choice.

So a consumer integration may legitimately add **a tool-library dependency** while adding **zero acture dependency** — that is the agent-written path, and it fully honours the dev-tool-first principle.

### Step 3 — Build it

- **Agent-written path:** write the integration directly in the user's project. The only thing it needs from acture is the *pattern* (how to iterate the registry, how to call `dispatch(id, params)`, how to read `keybinding` / `when` / schema off a `CommandRecord`). It needs nothing *imported* from acture unless the user is also using `acture` core for the registry itself. Reference the per-surface skill and, if helpful, the corresponding `acture-*` package's source as a worked example to adapt — not to import.
- **Package-reuse path:** install the `acture-*` package, wire it to the user's registry. The package takes the registry as input and translates; it never owns business logic.

### Step 4 — Record the choice

Note in the project's migration/adoption notes (or wherever decisions are tracked) which path was taken per consumer and why. A later session — or a `migration-graduate` pass — needs to know whether a dependency was a deliberate trade or an accident.

## When you are working ON a consumer-specific acture-* package

The same positioning applies inward:

- The package is an *optional accelerator*. Its README must document the hand-written alternative, not just `npm install`.
- It **translates** the registry to its target surface; it holds no business logic and makes no architectural decisions (hard-don't #3).
- It depends on exactly one tool library, declared as a peer dependency, and its docs frame that tool as the user's choice — naming it, not selling it.
- It must be independently installable and independently optional. Nothing else in acture may assume it is present.

## Checklist before you finish

- [ ] Did you present (or follow a stated preference for) the agent-written vs package-reuse choice — rather than defaulting to install?
- [ ] If you added an `acture-*` dependency, was it an explicit, recorded user decision?
- [ ] If you added a tool-library dependency, is it framed as the user's consumer code's dependency and the user's tool choice?
- [ ] Could the user have gotten a working consumer with zero acture dependency? (If no — you drifted. Fix it.)
- [ ] Did you load the per-surface skill (palette / hotkeys / mcp / ai / e2e / …) for the specific consumer, and `migration-*` skills if this is a strangler-fig context?

## See also

- `docs/positioning.md` — the canonical positioning this skill enforces.
- `acture-architecture-primer` — the eight consumer surfaces and the three primitives.
- `acture-hard-donts` — the merge checklist; #2 (no god-package) and #3 (adapters translate) are the ones this skill operationalises.
- Per-surface skills (`acture-palette-design`, and the consumer skills added over time) for the specifics of each surface.
Loading
Loading