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
16 changes: 16 additions & 0 deletions .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "mft-api",
"owner": {
"name": "Dan Oved",
"url": "https://github.com/oveddan"
},
"description": "MIDI Fighter Twister configuration tooling for coding agents.",
"plugins": [
{
"name": "mft-configurator",
"source": "./",
"description": "Inspect and configure a DJ TechTools MIDI Fighter Twister in plain language, through the guarded mft-config CLI.",
"category": "hardware"
}
]
}
23 changes: 23 additions & 0 deletions .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"name": "mft-configurator",
"displayName": "MIDI Fighter Twister Configurator",
"description": "Inspect and configure a DJ TechTools MIDI Fighter Twister in plain language, through the guarded mft-config CLI.",
"version": "0.1.0",
"author": {
"name": "Dan Oved",
"url": "https://github.com/oveddan"
},
"homepage": "https://github.com/oveddan/mft-api#readme",
"repository": "https://github.com/oveddan/mft-api",
"license": "MIT",
"keywords": [
"midi-fighter-twister",
"midi",
"djtechtools",
"hardware",
"sysex"
],
"skills": [
"./.claude/skills"
]
}
72 changes: 72 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Release

# Publishing is deliberately manual: Actions -> Release -> Run workflow.
# Nothing reaches npm without someone choosing to send it.
#
# The version comes from package.json. Bump it, merge, then run this. The job
# refuses a version that is already on npm, so a forgotten bump fails loudly
# here rather than as an opaque registry rejection after a full build.
#
# Authentication is npm trusted publishing (OIDC), so there is no NPM_TOKEN to
# rotate or leak. It has to be enabled once on npmjs.com:
# Settings -> Trusted publisher -> GitHub Actions -> this repo, workflow
# `release.yml`. Until that is done the publish step fails, and the fallback is
# `npm publish` from a logged-in machine.
on:
workflow_dispatch:

jobs:
publish:
name: Publish to npm
runs-on: ubuntu-latest
permissions:
# Pushing the release tag.
contents: write
# Required for trusted publishing; without it npm falls back to looking
# for a token and fails.
id-token: write
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
registry-url: https://registry.npmjs.org

# setup-node pins an npm that predates OIDC publishing on some images.
- name: Use an npm that supports trusted publishing
run: npm install -g npm@latest

- run: pnpm install --frozen-lockfile

- name: Read the version to publish
id: version
run: echo "version=$(node -p "require('./package.json').version")" >> "$GITHUB_OUTPUT"

# A forgotten version bump is the likeliest mistake here. `npm view` on an
# unpublished version exits 0 with empty output, so test the output rather
# than the exit status.
- name: Version is not already published
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
if [ -n "$(npm view "mft-config@$VERSION" version 2>/dev/null)" ]; then
echo "mft-config@$VERSION is already on npm; bump the version in package.json first" >&2
exit 1
fi
echo "publishing mft-config@$VERSION"

# `prepack` runs the full `check` (build + typecheck + tests), so this
# cannot publish something that does not build or pass tests.
- name: Publish
run: npm publish --provenance --access public

# Only after a successful publish, so a tag never points at a release that
# did not happen.
- name: Tag the released commit
env:
VERSION: ${{ steps.version.outputs.version }}
run: |
git tag "v$VERSION"
git push origin "v$VERSION"
43 changes: 42 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,32 @@ bootloader commands are always blocked. Live writes currently require firmware
## Install

Requires Node.js 20 or newer. Prebuilt MIDI binaries ship for macOS, Windows,
and Linux, so no compiler is needed on common platforms.
and Linux, so no compiler is needed on common platforms. Nothing below needs a
clone, a build, or a local toolchain.

### Claude Code

Two commands, and the agent can talk to the controller:

```sh
/plugin marketplace add oveddan/mft-api
/plugin install mft-configurator@mft-api
```

That installs the `mft-configurator` skill. It reaches the CLI through
`npx -y mft-config`, so there is no second install step — though a global
install (below) makes every command noticeably faster to start.

### Codex

Codex has no marketplace, so the skill is fetched directly. This copies only
the skill directory:

```sh
mkdir -p ~/.codex/skills/mft-configurator && curl -fsSL https://github.com/oveddan/mft-api/archive/refs/heads/main.tar.gz | tar -xz --strip-components=4 -C ~/.codex/skills/mft-configurator mft-api-main/.claude/skills/mft-configurator
```

### The CLI on its own

```sh
npm install -g mft-config
Expand All @@ -158,6 +183,9 @@ npx -y mft-config list
Every example below uses `mft-config`. The old `mft-export` name still works as
a deprecated alias and will be removed in a future release.

Upgrading, removing, and the details of both agent installs are in
[docs/agent-skill.md](docs/agent-skill.md).

**Run every command from the same directory.** `mft-config` writes its backups
and its single-use plan journal to `.mft-state/` relative to the current working
directory, so switching directories between `plan` and `apply` consults a
Expand Down Expand Up @@ -498,6 +526,19 @@ it steps around are real, and it is deliberately absent from the agent skill.
On Linux you need the ALSA development package required by RtMidi if you are
building the native dependency from source rather than using its prebuilds.

### Releasing

Publishing is manual. Bump the version in `package.json`, merge it, then run
the **Release** workflow from the Actions tab. Nothing reaches npm without
someone choosing to send it.

The workflow refuses a version that is already published, so a forgotten bump
fails immediately instead of part-way through. `prepack` runs the full check
before anything uploads, and the released commit is tagged `v<version>` only
after the publish succeeds. Authentication is npm trusted publishing, so there
is no token stored in the repository — it has to be enabled once on npmjs.com,
as [.github/workflows/release.yml](.github/workflows/release.yml) describes.

## License

This project is licensed under the MIT License. See the [LICENSE](LICENSE) file
Expand Down
51 changes: 31 additions & 20 deletions docs/agent-skill.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,47 @@ The `mft-configurator` skill lets Claude Code or Codex inspect and configure a
MIDI Fighter Twister in plain language. It drives the `mft-config` CLI; it never
talks to the device directly.

## 1. Install the CLI
No clone and no build is required for any path below.

## Claude Code: install the plugin

```sh
npm install -g mft-config
/plugin marketplace add oveddan/mft-api
/plugin install mft-configurator@mft-api
```

The skill also works with `npx -y mft-config` if you would rather not install
anything globally.
The plugin bundles the skill. `/plugin update` upgrades it, and
`/plugin uninstall mft-configurator@mft-api` removes it.

## 2. Install the skill
Working inside a checkout of this repository, Claude Code discovers the skill
from `.claude/skills/` automatically and the plugin is unnecessary.

No clone and no build — this fetches only the skill directory.
## Codex: fetch the skill directory

For Claude Code:
There is no marketplace equivalent, so this is a single command rather than
pretending parity exists. It fetches only the skill directory:

```sh
mkdir -p ~/.claude/skills/mft-configurator && curl -fsSL https://github.com/oveddan/mft-api/archive/refs/heads/main.tar.gz | tar -xz --strip-components=4 -C ~/.claude/skills/mft-configurator mft-api-main/.claude/skills/mft-configurator
mkdir -p ~/.codex/skills/mft-configurator && curl -fsSL https://github.com/oveddan/mft-api/archive/refs/heads/main.tar.gz | tar -xz --strip-components=4 -C ~/.codex/skills/mft-configurator mft-api-main/.claude/skills/mft-configurator
```

For Codex, the same command with a different destination:
It overwrites in place, so re-running it upgrades. Delete the destination
directory first if you want files removed upstream to disappear too.

```sh
mkdir -p ~/.codex/skills/mft-configurator && curl -fsSL https://github.com/oveddan/mft-api/archive/refs/heads/main.tar.gz | tar -xz --strip-components=4 -C ~/.codex/skills/mft-configurator mft-api-main/.claude/skills/mft-configurator
```
The same command with `~/.claude/skills/mft-configurator` as the destination
still works for Claude Code, if you would rather not use the plugin.

Both commands overwrite in place, so re-running them upgrades. Delete the
destination directory first if you want files removed upstream to disappear too.
## The CLI

Working inside a checkout of this repository, Claude Code discovers the skill
automatically and neither step 2 command is needed.
The skill invokes `npx -y mft-config` when the command is not on `PATH`, so
this is optional. Installing it globally removes the npx startup cost from
every command:

```sh
npm install -g mft-config
```

## 3. Use it
## Use it

Invoke `/mft-configurator` in Claude Code or `$mft-configurator` in Codex, or
just ask the agent to inspect or configure a Twister.
Expand All @@ -47,13 +56,15 @@ controller requires a separate, explicit instruction.

`SKILL.md` uses the portable Agent Skills format understood by both Claude Code
and Codex. The optional `agents/openai.yaml`, generated with Codex's skill
creator, adds Codex UI metadata; Claude Code ignores it.
creator, adds Codex UI metadata; Claude Code ignores it. Both the plugin and the
Codex one-liner serve the same single copy of the skill in `.claude/skills/`, so
there is no second copy to keep in sync.

**Run the agent from one consistent working directory.** `mft-config` writes its
backups and its single-use plan journal to `.mft-state/` relative to the current
working directory, so an `apply` run from a different directory than an earlier
one consults a different journal.

A Claude Code plugin that installs the skill and an MCP server in a single step
is planned; see [#8](https://github.com/oveddan/mft-api/issues/8) and
An MCP server, so that one install serves any agent that speaks the protocol
rather than one skill copy per tool, is still open; see
[#12](https://github.com/oveddan/mft-api/issues/12).
Loading