bitwig-agent 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. bitwig_agent-0.1.1/.github/workflows/aur.yml +95 -0
  2. bitwig_agent-0.1.1/.github/workflows/ci.yml +112 -0
  3. bitwig_agent-0.1.1/.github/workflows/publish-pypi.yml +204 -0
  4. bitwig_agent-0.1.1/.gitignore +40 -0
  5. bitwig_agent-0.1.1/CONTRIBUTING.md +103 -0
  6. bitwig_agent-0.1.1/INSTALL.md +123 -0
  7. bitwig_agent-0.1.1/LICENSE +21 -0
  8. bitwig_agent-0.1.1/PKG-INFO +98 -0
  9. bitwig_agent-0.1.1/PROTOCOL.md +364 -0
  10. bitwig_agent-0.1.1/README.md +70 -0
  11. bitwig_agent-0.1.1/SECURITY.md +15 -0
  12. bitwig_agent-0.1.1/THIRD_PARTY_NOTICE.md +55 -0
  13. bitwig_agent-0.1.1/USAGE.md +83 -0
  14. bitwig_agent-0.1.1/VERIFICATION.md +125 -0
  15. bitwig_agent-0.1.1/docs/README.md +29 -0
  16. bitwig_agent-0.1.1/docs/architecture.md +85 -0
  17. bitwig_agent-0.1.1/docs/packaging.md +123 -0
  18. bitwig_agent-0.1.1/examples/grid_music.py +420 -0
  19. bitwig_agent-0.1.1/examples/mcp-config.json +9 -0
  20. bitwig_agent-0.1.1/extension/src/main/java/BitwigAgent613GridInsertion.java +31 -0
  21. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/ActionModule.java +59 -0
  22. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613DeviceTargetAccess.java +36 -0
  23. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridAdapter.java +393 -0
  24. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridBooleanPanelAccess.java +53 -0
  25. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridConnectionAccess.java +38 -0
  26. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridInsertionAccess.java +149 -0
  27. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridModuleAccess.java +76 -0
  28. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridModuleNameAccess.java +36 -0
  29. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridParameterContext.java +63 -0
  30. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridParameterWriter.java +44 -0
  31. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613GridTopologyContext.java +46 -0
  32. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613ModulatorAdapter.java +145 -0
  33. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613ReadContextAccess.java +39 -0
  34. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613Runtime.java +151 -0
  35. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Bitwig613StringPanelAccess.java +44 -0
  36. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/BitwigAgentExtension.java +35 -0
  37. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/BitwigAgentExtensionDefinition.java +24 -0
  38. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/BoundedJson.java +26 -0
  39. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/DeviceModule.java +655 -0
  40. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/DeviceSources.java +499 -0
  41. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/DiscoveryModule.java +160 -0
  42. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridAdapter.java +26 -0
  43. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridBooleanPanelWriter.java +65 -0
  44. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridConnectionWriter.java +215 -0
  45. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridInsertionBridge.java +14 -0
  46. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridInsertionWriter.java +294 -0
  47. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridModule.java +244 -0
  48. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridModuleNameWriter.java +164 -0
  49. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridModuleWriter.java +223 -0
  50. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridParameterContext.java +148 -0
  51. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridParameterWriter.java +141 -0
  52. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridSnapshotReader.java +571 -0
  53. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridTopologyContext.java +83 -0
  54. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/GridTopologyQuarantine.java +95 -0
  55. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/HostBridge.java +91 -0
  56. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/HostModule.java +12 -0
  57. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/HostOperation.java +27 -0
  58. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/HostServices.java +168 -0
  59. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/LauncherModule.java +612 -0
  60. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/MixModule.java +426 -0
  61. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/ModulatorAdapter.java +12 -0
  62. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/ModulatorModule.java +101 -0
  63. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/ModulatorSnapshotReader.java +277 -0
  64. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/NativeDeviceTarget.java +69 -0
  65. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/NativeReadContext.java +101 -0
  66. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/ParameterModule.java +279 -0
  67. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/Params.java +80 -0
  68. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/RpcException.java +13 -0
  69. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/RpcServer.java +236 -0
  70. bitwig_agent-0.1.1/extension/src/main/java/dev/bitwigagent/TransportModule.java +181 -0
  71. bitwig_agent-0.1.1/extension/src/main/resources/META-INF/services/com.bitwig.extension.ExtensionDefinition +1 -0
  72. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/Bitwig613RuntimeTest.java +58 -0
  73. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/DeviceModuleTest.java +977 -0
  74. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/GridInsertionWriterTest.java +367 -0
  75. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/GridModuleNameWriterTest.java +328 -0
  76. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/GridModuleTest.java +810 -0
  77. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/GridSnapshotReaderTest.java +1726 -0
  78. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/HostBridgeTest.java +1137 -0
  79. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/LauncherModuleTest.java +898 -0
  80. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/MixModuleTest.java +438 -0
  81. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/ModulatorModuleTest.java +286 -0
  82. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/ModulatorSnapshotReaderTest.java +313 -0
  83. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/NativeReadContextTest.java +119 -0
  84. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/RpcServerTest.java +275 -0
  85. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/TransportMixFixture.java +233 -0
  86. bitwig_agent-0.1.1/extension/src/test/java/dev/bitwigagent/TransportModuleTest.java +124 -0
  87. bitwig_agent-0.1.1/pyproject.toml +51 -0
  88. bitwig_agent-0.1.1/scripts/build.py +85 -0
  89. bitwig_agent-0.1.1/scripts/check.py +87 -0
  90. bitwig_agent-0.1.1/scripts/evidence_audio.py +93 -0
  91. bitwig_agent-0.1.1/scripts/evidence_mix.py +33 -0
  92. bitwig_agent-0.1.1/scripts/smoke-mcp-java.py +144 -0
  93. bitwig_agent-0.1.1/scripts/smoke-native.py +312 -0
  94. bitwig_agent-0.1.1/scripts/smoke-package.py +56 -0
  95. bitwig_agent-0.1.1/scripts/test-java.py +57 -0
  96. bitwig_agent-0.1.1/skills/bitwig-agent/LICENSE +21 -0
  97. bitwig_agent-0.1.1/skills/bitwig-agent/SKILL.md +40 -0
  98. bitwig_agent-0.1.1/skills/bitwig-agent/references/grid-and-recipes.md +39 -0
  99. bitwig_agent-0.1.1/skills/bitwig-agent/references/setup-and-validation.md +25 -0
  100. bitwig_agent-0.1.1/skills/bitwig-agent/references/targeting-and-evidence.md +48 -0
  101. bitwig_agent-0.1.1/src/bitwig_agent/__init__.py +2 -0
  102. bitwig_agent-0.1.1/src/bitwig_agent/__main__.py +6 -0
  103. bitwig_agent-0.1.1/src/bitwig_agent/catalog.py +101 -0
  104. bitwig_agent-0.1.1/src/bitwig_agent/cli.py +118 -0
  105. bitwig_agent-0.1.1/src/bitwig_agent/client.py +118 -0
  106. bitwig_agent-0.1.1/src/bitwig_agent/install.py +130 -0
  107. bitwig_agent-0.1.1/src/bitwig_agent/schema.py +372 -0
  108. bitwig_agent-0.1.1/src/bitwig_agent/server.py +60 -0
  109. bitwig_agent-0.1.1/tests/conftest.py +73 -0
  110. bitwig_agent-0.1.1/tests/test_cli.py +436 -0
  111. bitwig_agent-0.1.1/tests/test_client.py +118 -0
  112. bitwig_agent-0.1.1/tests/test_install_extension.py +264 -0
  113. bitwig_agent-0.1.1/tests/test_mcp.py +457 -0
  114. bitwig_agent-0.1.1/tests/test_music_recipe.py +200 -0
  115. bitwig_agent-0.1.1/tests/test_native_evidence.py +118 -0
  116. bitwig_agent-0.1.1/tests/test_native_smoke.py +211 -0
  117. bitwig_agent-0.1.1/tests/test_schema.py +646 -0
  118. bitwig_agent-0.1.1/third-party/GSON-LICENSE.txt +202 -0
  119. bitwig_agent-0.1.1/uv.lock +1201 -0
@@ -0,0 +1,95 @@
1
+ name: Arch package
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: read
10
+
11
+ concurrency:
12
+ group: arch-${{ github.ref }}
13
+ cancel-in-progress: false
14
+
15
+ jobs:
16
+ package:
17
+ runs-on: ubuntu-24.04
18
+ timeout-minutes: 25
19
+ container:
20
+ image: archlinux:base-devel@sha256:3cbf69d2d5958d6a294f3722c5668e6187c4df8e00fa27f72352f0bf83e495e1
21
+ steps:
22
+ - name: Install distro build and check dependencies inside the disposable container
23
+ run: >-
24
+ pacman -Syu --noconfirm --needed
25
+ git python-build python-hatchling python-installer python-mcp python-pydantic
26
+ python-pytest python-numpy python-scipy python-soundfile namcap
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
28
+ with:
29
+ persist-credentials: false
30
+ - name: Require matching release, Python and Arch versions
31
+ id: version
32
+ env:
33
+ RELEASE_TAG: ${{ github.event.release.tag_name }}
34
+ run: |
35
+ python - <<'PY'
36
+ import os
37
+ from pathlib import Path
38
+ import tomllib
39
+
40
+ version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"]
41
+ versions = [
42
+ line.partition("=")[2].strip()
43
+ for line in Path("packaging/aur/.SRCINFO").read_text().splitlines()
44
+ if line.strip().startswith("pkgver =")
45
+ ]
46
+ if versions != [version]:
47
+ raise SystemExit("Arch recipe version does not match Python metadata")
48
+ tag = os.environ.get("RELEASE_TAG", "")
49
+ ref = os.environ["GITHUB_REF"]
50
+ if not tag and ref.startswith("refs/tags/"):
51
+ tag = ref.removeprefix("refs/tags/")
52
+ if tag and tag != f"v{version}":
53
+ raise SystemExit("Selected release tag does not match package versions")
54
+ with open(os.environ["GITHUB_OUTPUT"], "a") as output:
55
+ print(f"version={version}", file=output)
56
+ print(f"Arch release version: {version}")
57
+ PY
58
+ - name: Prepare an unprivileged package builder
59
+ run: |
60
+ useradd --create-home builder
61
+ install -d -o builder -g builder /home/builder/package
62
+ cp packaging/aur/PKGBUILD packaging/aur/.SRCINFO packaging/aur/LICENSE /home/builder/package/
63
+ chown -R builder:builder /home/builder/package
64
+ - name: Build the real release package and run its checks
65
+ working-directory: /home/builder/package
66
+ run: |
67
+ runuser -u builder -- makepkg --printsrcinfo | diff - .SRCINFO
68
+ runuser -u builder -- makepkg --cleanbuild --noconfirm
69
+ runuser -u builder -- makepkg --force --noconfirm
70
+ python - <<'PY'
71
+ from pathlib import Path
72
+ import subprocess
73
+
74
+ result = subprocess.run(
75
+ ["namcap", "PKGBUILD", *sorted(Path(".").glob("bitwig-agent-*.pkg.tar.zst"))],
76
+ text=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
77
+ )
78
+ print(result.stdout, end="")
79
+ if result.returncode or any(" E: " in line for line in result.stdout.splitlines()):
80
+ raise SystemExit(1)
81
+ PY
82
+ - name: Install only inside the disposable container and exercise the consumer
83
+ env:
84
+ EXPECTED_VERSION: ${{ steps.version.outputs.version }}
85
+ run: |
86
+ # The base image's NoExtract omits docs; test the complete owned package.
87
+ printf '[options]\nArchitecture = auto\nSigLevel = Required DatabaseOptional\nLocalFileSigLevel = Optional\n' \
88
+ > /tmp/bitwig-pacman.conf
89
+ pacman --config /tmp/bitwig-pacman.conf -U --noconfirm /home/builder/package/bitwig-agent-*.pkg.tar.zst
90
+ runuser -u builder -- python -I scripts/smoke-package.py --expected-version "$EXPECTED_VERSION"
91
+ runuser -u builder -- bitwig-agent-install \
92
+ --extension /usr/share/bitwig-agent/BitwigAgent.bwextension
93
+ cmp /usr/share/bitwig-agent/BitwigAgent.bwextension \
94
+ '/home/builder/Bitwig Studio/Extensions/BitwigAgent.bwextension'
95
+ pacman -Qkk bitwig-agent
@@ -0,0 +1,112 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ci-${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ python:
18
+ name: Python ${{ matrix.python }} / MCP ${{ matrix.mcp }}
19
+ runs-on: ubuntu-24.04
20
+ timeout-minutes: 15
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ python: ["3.11", "3.14"]
25
+ mcp: ["locked"]
26
+ include:
27
+ - python: "3.11"
28
+ mcp: "1.29.1"
29
+ steps:
30
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
31
+ with:
32
+ persist-credentials: false
33
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
34
+ with:
35
+ version: "0.13.5"
36
+ python-version: ${{ matrix.python }}
37
+ - name: Install locked development and audio-analysis dependencies
38
+ run: uv sync --locked --group native-music
39
+ - name: Install the minimum supported MCP SDK
40
+ if: matrix.mcp != 'locked'
41
+ run: uv pip install --python .venv/bin/python "mcp==${{ matrix.mcp }}"
42
+ - name: Run host-free Python checks
43
+ run: uv run --no-sync python scripts/check.py --layer offline
44
+
45
+ package:
46
+ name: Package / Python ${{ matrix.python }} / MCP ${{ matrix.mcp }}
47
+ runs-on: ubuntu-24.04
48
+ timeout-minutes: 10
49
+ strategy:
50
+ fail-fast: false
51
+ matrix:
52
+ include:
53
+ - python: "3.14"
54
+ mcp: "current"
55
+ - python: "3.11"
56
+ mcp: "1.29.1"
57
+ steps:
58
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
59
+ with:
60
+ persist-credentials: false
61
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
62
+ with:
63
+ version: "0.13.5"
64
+ python-version: ${{ matrix.python }}
65
+ - name: Build source and wheel distributions
66
+ run: uv build --no-sources
67
+ - name: Exercise installed wheel and sdist consumers
68
+ env:
69
+ MCP_VERSION: ${{ matrix.mcp }}
70
+ PYTHON_VERSION: ${{ matrix.python }}
71
+ run: |
72
+ for distribution in dist/*.whl dist/*.tar.gz; do
73
+ consumer="$(mktemp -d "$RUNNER_TEMP/package-consumer.XXXXXX")"
74
+ uv venv --python "$PYTHON_VERSION" "$consumer/venv"
75
+ dependencies=("$PWD/$distribution")
76
+ if [[ "$MCP_VERSION" != current ]]; then
77
+ dependencies+=("mcp==$MCP_VERSION")
78
+ fi
79
+ uv pip install --no-cache --python "$consumer/venv/bin/python" "${dependencies[@]}"
80
+ "$consumer/venv/bin/python" -I scripts/smoke-package.py
81
+ done
82
+ - name: Validate the Agent Skills folder with the reference CLI
83
+ run: >-
84
+ uvx --from
85
+ 'git+https://github.com/agentskills/agentskills.git@69ef37e9424c0a7ea9dd2293b559e43ec8176379#subdirectory=skills-ref'
86
+ skills-ref validate skills/bitwig-agent
87
+
88
+ secrets:
89
+ name: Reachable-history secret scan
90
+ runs-on: ubuntu-24.04
91
+ timeout-minutes: 10
92
+ steps:
93
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
94
+ with:
95
+ fetch-depth: 0
96
+ persist-credentials: false
97
+ - name: Install checksum-pinned Gitleaks
98
+ run: |
99
+ curl --fail --silent --show-error --location \
100
+ https://github.com/gitleaks/gitleaks/releases/download/v8.30.1/gitleaks_8.30.1_linux_x64.tar.gz \
101
+ --output "$RUNNER_TEMP/gitleaks.tar.gz"
102
+ printf '%s %s\n' \
103
+ '551f6fc83ea457d62a0d98237cbad105af8d557003051f41f3e7ca7b3f2470eb' \
104
+ "$RUNNER_TEMP/gitleaks.tar.gz" | sha256sum --check
105
+ tar -xzf "$RUNNER_TEMP/gitleaks.tar.gz" -C "$RUNNER_TEMP" gitleaks
106
+ - name: Scan all reachable commits without suppression comments
107
+ run: |
108
+ "$RUNNER_TEMP/gitleaks" git . \
109
+ --log-opts='--all --full-history -m' \
110
+ --redact=100 --ignore-gitleaks-allow \
111
+ --gitleaks-ignore-path "$RUNNER_TEMP/no-gitleaks-ignore" \
112
+ --no-banner --no-color
@@ -0,0 +1,204 @@
1
+ name: Verify release / publish to PyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ publish:
7
+ description: Publish the verified release to PyPI (requires configured Trusted Publisher and environment approval)
8
+ required: true
9
+ type: boolean
10
+ default: false
11
+
12
+ permissions: {}
13
+
14
+ concurrency:
15
+ group: pypi-${{ github.ref }}
16
+ cancel-in-progress: false
17
+
18
+ jobs:
19
+ verify:
20
+ name: Verify published GitHub release artifacts
21
+ runs-on: ubuntu-24.04
22
+ timeout-minutes: 15
23
+ permissions:
24
+ contents: read
25
+ outputs:
26
+ version: ${{ steps.release.outputs.version }}
27
+ steps:
28
+ - name: Require a version tag
29
+ shell: bash
30
+ run: |
31
+ if [[ ! "$GITHUB_REF" =~ ^refs/tags/v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; then
32
+ echo 'Dispatch this workflow on a vX.Y.Z tag, not a branch.' >&2
33
+ exit 1
34
+ fi
35
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
36
+ with:
37
+ persist-credentials: false
38
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
39
+ with:
40
+ version: "0.13.5"
41
+ python-version: "3.11"
42
+ enable-cache: false
43
+ - name: Download and verify the reviewed release (never rebuild for promotion)
44
+ id: release
45
+ env:
46
+ GH_TOKEN: ${{ github.token }}
47
+ run: |
48
+ uv run --no-project --python 3.11 python - <<'PY'
49
+ from collections import Counter
50
+ from email.parser import BytesParser
51
+ import hashlib
52
+ import json
53
+ import os
54
+ from pathlib import Path
55
+ import re
56
+ import shutil
57
+ import subprocess
58
+ import tarfile
59
+ import tomllib
60
+ import zipfile
61
+
62
+ tag = os.environ["GITHUB_REF_NAME"]
63
+ version = tag.removeprefix("v")
64
+ project = tomllib.loads(Path("pyproject.toml").read_text())["project"]
65
+ if project["name"] != "bitwig-agent" or project["version"] != version:
66
+ raise SystemExit("Tag does not match pyproject.toml package/version")
67
+ wheel = f"bitwig_agent-{version}-py3-none-any.whl"
68
+ sdist = f"bitwig_agent-{version}.tar.gz"
69
+ extension = "BitwigAgent.bwextension"
70
+ required = {wheel, sdist, extension}
71
+ repo = os.environ["GITHUB_REPOSITORY"]
72
+ release = json.loads(subprocess.check_output([
73
+ "gh", "release", "view", tag, "--repo", repo,
74
+ "--json", "tagName,isDraft,assets",
75
+ ], text=True))
76
+ if release["tagName"] != tag or release["isDraft"]:
77
+ raise SystemExit("Expected a published GitHub release for this tag")
78
+ counts = Counter(asset["name"] for asset in release["assets"])
79
+ if any(counts[name] != 1 for name in required | {"SHA256SUMS"}):
80
+ raise SystemExit("Release must contain exactly one of each required asset")
81
+ downloads = Path(os.environ["RUNNER_TEMP"]) / "reviewed-release"
82
+ downloads.mkdir()
83
+ command = ["gh", "release", "download", tag, "--repo", repo, "--dir", str(downloads)]
84
+ for name in sorted(required | {"SHA256SUMS"}):
85
+ command.extend(["--pattern", name])
86
+ subprocess.run(command, check=True)
87
+ checksums = {}
88
+ for line in (downloads / "SHA256SUMS").read_text().splitlines():
89
+ match = re.fullmatch(r"([0-9a-fA-F]{64}) [ *]([^/\\\s]+)", line)
90
+ if match is None:
91
+ raise SystemExit(f"Malformed SHA256SUMS entry: {line!r}")
92
+ digest, name = match.groups()
93
+ if name in checksums:
94
+ raise SystemExit(f"Ambiguous checksum for {name}")
95
+ checksums[name] = digest.lower()
96
+ if set(checksums) != required:
97
+ raise SystemExit("SHA256SUMS must name exactly the wheel, sdist, and extension")
98
+ for name, expected in checksums.items():
99
+ with (downloads / name).open("rb") as stream:
100
+ actual = hashlib.file_digest(stream, "sha256").hexdigest()
101
+ if actual != expected:
102
+ raise SystemExit(f"SHA256 mismatch: {name}")
103
+ print(f"Verified SHA256 {actual} {name}", flush=True)
104
+
105
+ def check_metadata(data, source):
106
+ metadata = BytesParser().parsebytes(data)
107
+ if metadata.get_all("Name") != ["bitwig-agent"] or metadata.get_all("Version") != [version]:
108
+ raise SystemExit(f"Package name/version mismatch in {source}")
109
+
110
+ with zipfile.ZipFile(downloads / wheel) as archive:
111
+ entries = [entry for entry in archive.infolist()
112
+ if entry.filename.endswith(".dist-info/METADATA")]
113
+ if len(entries) != 1:
114
+ raise SystemExit("Expected exactly one wheel METADATA")
115
+ check_metadata(archive.read(entries[0]), wheel)
116
+ with tarfile.open(downloads / sdist, "r:gz") as archive:
117
+ entries = [entry for entry in archive.getmembers()
118
+ if entry.name == f"bitwig_agent-{version}/PKG-INFO"]
119
+ if len(entries) != 1 or not entries[0].isfile():
120
+ raise SystemExit("Expected exactly one regular sdist PKG-INFO")
121
+ with archive.extractfile(entries[0]) as stream:
122
+ check_metadata(stream.read(), sdist)
123
+ # Only these original Python distributions can reach the publishing job.
124
+ destination = Path("dist")
125
+ destination.mkdir()
126
+ for name in (wheel, sdist):
127
+ shutil.copyfile(downloads / name, destination / name)
128
+ with open(os.environ["GITHUB_OUTPUT"], "a") as output:
129
+ output.write(f"version={version}\n")
130
+ PY
131
+ - name: Smoke the actual release wheel and sdist outside the checkout
132
+ env:
133
+ RELEASE_VERSION: ${{ steps.release.outputs.version }}
134
+ run: |
135
+ for distribution in dist/*.whl dist/*.tar.gz; do
136
+ consumer="$(mktemp -d "$RUNNER_TEMP/release-consumer.XXXXXX")"
137
+ uv venv --python 3.11 "$consumer/venv"
138
+ # No cache: the sdist must really build, not reuse the release wheel.
139
+ uv pip install --no-cache --python "$consumer/venv/bin/python" \
140
+ "$PWD/$distribution" 'mcp==1.29.1'
141
+ "$consumer/venv/bin/python" -I scripts/smoke-package.py \
142
+ --expected-version "$RELEASE_VERSION"
143
+ done
144
+ - name: Preserve verified Python distributions for promotion
145
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
146
+ with:
147
+ name: verified-python-distributions
148
+ path: |
149
+ dist/*.whl
150
+ dist/*.tar.gz
151
+ if-no-files-found: error
152
+ retention-days: 7
153
+ - name: Report verification (not publication)
154
+ env:
155
+ RELEASE_VERSION: ${{ steps.release.outputs.version }}
156
+ PUBLISH_REQUESTED: ${{ inputs.publish }}
157
+ run: |
158
+ {
159
+ echo "## GitHub release v$RELEASE_VERSION verified"
160
+ echo 'Verified the wheel, sdist, and extension SHA256 checksums and Python package/tag versions.'
161
+ echo 'Installed wheel and sdist consumers passed offline CLI and real MCP discovery with Python 3.11 / MCP 1.29.1.'
162
+ echo 'No native Bitwig test or PyPI upload occurred in this job.'
163
+ if [[ "$PUBLISH_REQUESTED" == true ]]; then
164
+ echo 'Publication was requested; only the separate environment-gated publish job can report an upload.'
165
+ else
166
+ echo 'Verification-only run: publication was not requested.'
167
+ fi
168
+ } >> "$GITHUB_STEP_SUMMARY"
169
+
170
+ publish:
171
+ name: Publish verified artifacts to PyPI
172
+ needs: verify
173
+ if: inputs.publish
174
+ runs-on: ubuntu-24.04
175
+ timeout-minutes: 10
176
+ environment:
177
+ name: pypi
178
+ url: https://pypi.org/project/bitwig-agent/
179
+ permissions:
180
+ id-token: write
181
+ steps:
182
+ # Deliberately no checkout, builds, installs of this package, or source execution.
183
+ - uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2
184
+ with:
185
+ version: "0.13.5"
186
+ enable-cache: false
187
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
188
+ with:
189
+ name: verified-python-distributions
190
+ path: dist/
191
+ - name: Generate PEP 740 publish attestations
192
+ uses: astral-sh/attest-action@39b6ce43875c196a579e31635b11aa2a2036384a # v0.0.7
193
+ with:
194
+ paths: dist/*
195
+ - name: Publish with mandatory OIDC Trusted Publishing
196
+ run: uv publish --trusted-publishing always dist/*.whl dist/*.tar.gz
197
+ - name: Report successful publication
198
+ env:
199
+ RELEASE_VERSION: ${{ needs.verify.outputs.version }}
200
+ run: |
201
+ {
202
+ echo "## Published bitwig-agent $RELEASE_VERSION to PyPI"
203
+ echo 'Uploaded the verified GitHub release wheel and sdist with PEP 740 publish attestations via OIDC Trusted Publishing.'
204
+ } >> "$GITHUB_STEP_SUMMARY"
@@ -0,0 +1,40 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ build/
7
+ .deps/
8
+ *.egg-info/
9
+ .DS_Store
10
+ dist/
11
+ .package-venv/
12
+
13
+ # Local credentials and runtime configuration.
14
+ .env
15
+ .env.*
16
+ !.env.example
17
+ *.pem
18
+ *.key
19
+ *.p12
20
+ *.pfx
21
+
22
+ # Private development evidence and continuation records are not publication inputs.
23
+ /runs/
24
+ /research/
25
+ /review/
26
+ /docs/history/
27
+ /AGENTS.md
28
+ /HANDOFF.md
29
+ /scripts/grid-compatibility.py
30
+ /scripts/inventory-api.py
31
+ /tests/grid-cases.json
32
+
33
+ # Native projects, renders, host binaries and locally built extensions.
34
+ *.bwproject
35
+ *.bwpreset
36
+ *.wav
37
+ *.bwextension
38
+ *.jar
39
+ *.class
40
+ *.so
@@ -0,0 +1,103 @@
1
+ # Contributing
2
+
3
+ Keep changes focused on helping agents complete real Bitwig tasks. Domain operations belong in their existing modules; transport, validation and native bindings remain separate. Do not add automatic retries or GUI fallback for uncertain writes.
4
+
5
+ ## Source setup
6
+
7
+ End users should use the [released wheel and extension](README.md#quickstart). Development requires a checkout, Python 3.11+, [uv](https://docs.astral.sh/uv/getting-started/installation/), **JDK 25+**, and your own licensed Bitwig installation with its API 25 host JAR. The Bitwig 6.1.3 loader superclass uses class-file version 69, so JDK 25 is needed to compile/run Java checks; generated extension classes still target Java 11.
8
+
9
+ From the repository root:
10
+
11
+ ```sh
12
+ uv sync --locked
13
+ export BITWIG_API_JAR=/path/to/installed/bitwig.jar
14
+ export JAVAC=/path/to/jdk25/bin/javac
15
+ export JAVA=/path/to/jdk25/bin/java
16
+ uv run --locked python scripts/build.py
17
+ uv run --locked bitwig-agent-install --extension build/BitwigAgent.bwextension
18
+ ```
19
+
20
+ The API JAR defaults to `/opt/bitwig-studio/bin/bitwig.jar`; override it for your installation. The build downloads and verifies pinned Gson on first use. Neither the proprietary host JAR nor JDK is bundled. Installation does not enable the controller: follow [the enable/connect steps](README.md#2-enable-in-bitwig). For a checkout-based MCP configuration, run `uv run --locked bitwig-agent-install --mcp-config`; keep the checkout environment available to the client.
21
+
22
+ ## Development checks
23
+
24
+ Use Python 3.11+ and uv. Install optional audio-analysis dependencies so the offline suite exercises its PCM checks rather than skipping them:
25
+
26
+ ```sh
27
+ uv sync --locked --group native-music
28
+ uv run --locked python scripts/check.py --layer offline
29
+ ```
30
+
31
+ For the Java build, simulated-host checks and real MCP/Java fixture, install JDK 25+ and supply your own compatible Bitwig API JAR:
32
+
33
+ ```sh
34
+ export BITWIG_API_JAR=/path/to/installed/bitwig.jar
35
+ export JAVAC=/path/to/jdk25/bin/javac
36
+ export JAVA=/path/to/jdk25/bin/java
37
+ uv run --locked python scripts/build.py
38
+ uv run --locked python scripts/check.py
39
+ ```
40
+
41
+ The default checks do not launch Bitwig. See [VERIFICATION.md](VERIFICATION.md) for layer boundaries. CI covers host-free Python checks, minimum supported MCP, Python package consumption, skill format and a reachable-history secret scan; local Arch packaging is a separate downstream check. None claims to build against or test a live proprietary host. Consult actual workflow output rather than treating configured jobs as passing evidence.
42
+
43
+ ## Changes and bug reports
44
+
45
+ - Describe the observable behavior, affected methods and checks actually run. Add a deterministic regression test for a consumer-visible bug when practical.
46
+ - Keep MCP and CLI schemas consistent with Java validation and [PROTOCOL.md](PROTOCOL.md).
47
+ - Distinguish dispatch, model readback, GUI completion, audio output and persistence. Do not report an unknown write as failed-and-safe-to-repeat.
48
+ - Native work requires a disposable project and one designated writer. Never use a user's active project as an automatic test fixture.
49
+ - Review staged files before committing. Do not submit credentials, private conversations, raw machine/process snapshots, original tool-call identifiers, personal paths, Bitwig host binaries or proprietary factory assets. Use minimal synthetic reproductions and redacted diagnostics.
50
+ - Preserve third-party notices. Project contributions are distributed under the [MIT License](LICENSE); third-party material retains its own applicable license.
51
+
52
+ For security-sensitive issues, use the private route in [SECURITY.md](SECURITY.md), not a public issue containing exploit details or private data.
53
+
54
+ ## Release procedure
55
+
56
+ See [packaging and release promotion](docs/packaging.md) for the complete artifact, Arch and PyPI contract. Releases are built locally against a maintainer's licensed Bitwig JAR; public CI does not have that dependency. The commands below use **0.1.1**; they are instructions, not evidence that any check ran.
57
+
58
+ 1. Start from reviewed source, align Python/MCP/extension versions and installation links, and run the applicable [layered checks](VERIFICATION.md). Keep actual results; list native checks not performed.
59
+ 2. Build the Python wheel **and sdist**, plus the matching extension:
60
+
61
+ ```sh
62
+ uv sync --locked
63
+ uv build
64
+ uv run --locked python scripts/build.py
65
+ sha256sum dist/bitwig_agent-0.1.1-py3-none-any.whl dist/bitwig_agent-0.1.1.tar.gz build/BitwigAgent.bwextension
66
+ ```
67
+
68
+ 3. Create `SHA256SUMS` from those actual hashes with exactly three unique **bare asset filenames**, removing local `dist/` and `build/` prefixes. Inspect artifact contents and third-party notices. Never upload the proprietary host JAR, factory assets or private machine/evidence data.
69
+ 4. Finalize [the Arch recipe](https://github.com/BANANASJIM/bitwig-agent/tree/main/packaging/aur) from those exact candidate artifacts and regenerate `.SRCINFO` **before tagging**. Validate it in an isolated Arch environment; its source cache may be prefilled with the exact candidate sdist and version-aliased extension. `packaging/` is excluded from the sdist, so updating its hashes does not require rebuilding that sdist.
70
+ 5. Commit the reviewed source, recipe and metadata, then tag it as `v0.1.1`. Publish the same wheel, sdist, extension and manifest to its GitHub release. Include the actual tested platform/host scope and unresolved limitations. Do not mutate previous release artifacts.
71
+ 6. Exercise the real GitHub wheel/download path in an isolated environment outside the checkout, using an isolated extension destination, offline CLI and the generated configuration's MCP handshake. Confirm the release-triggered Arch workflow builds the matching version from published downloads. A live status/editing check is separate and requires permission, one writer and a disposable project; recipe verification is not an AUR upload.
72
+ 7. Run `publish-pypi.yml` on the version tag with `publish=false` for promotion validation. Only an explicitly authorized publication with the configured `pypi` environment and Trusted Publisher may use `publish=true`. Promote the same reviewed artifacts, not a separate rebuild. See [external account prerequisites](docs/packaging.md#external-accountenvironment-prerequisites).
73
+
74
+ Neither a pending PyPI publisher nor an AUR recipe establishes public package availability. Keep GitHub wheel installation as the documented path until the relevant registry/version actually exists.
75
+
76
+ ## Agent skill maintenance
77
+
78
+ The portable skill is [`skills/bitwig-agent`](https://github.com/BANANASJIM/bitwig-agent/tree/main/skills/bitwig-agent). Keep its main `SKILL.md` short; place focused guidance one directory level down in `references/`, with every reference directly reachable from `SKILL.md`. Bundle its MIT `LICENSE` so the folder can be copied alone. Links outside that folder must use public repository URLs, not checkout-relative paths. Do not embed host identities, private paths, credentials, global client configuration changes or a tool permission grant.
79
+
80
+ Use the [Agent Skills specification](https://agentskills.io/specification) and the demonstration `skills-ref` validator pinned to the reviewed source commit:
81
+
82
+ ```sh
83
+ uvx --from "git+https://github.com/agentskills/agentskills.git@69ef37e9424c0a7ea9dd2293b559e43ec8176379#subdirectory=skills-ref" skills-ref validate skills/bitwig-agent
84
+ ```
85
+
86
+ This command fetches a validation tool; it is not a production DAW dependency. Format/frontmatter validation does **not** establish correct tool use, native behavior, compatibility, permissions or musical acceptance. Separately review the copied folder's local references and safety instructions: fresh schema/target discovery, explicit permission, unknown-stop discipline and no implicit GUI fallback.
87
+
88
+ ## Repository map and architecture
89
+
90
+ See [architecture and ownership](docs/architecture.md) for the detailed public-code walkthrough. Python MCP stdio and CLI entrypoints share a strict schema/catalog and loopback client. The Java extension dispatches bounded newline-delimited JSON requests through host scheduling into separate domains. Bitwig owns the project/audio engine; the bridge is not a complete project mirror and never automatically retries requests.
91
+
92
+ | Path | Responsibility |
93
+ |---|---|
94
+ | `src/bitwig_agent/` | Schemas/catalog, transport, MCP, CLI and release installer |
95
+ | `extension/src/main/java/dev/bitwigagent/` | Host services, domains and bounded native adapters |
96
+ | `extension/src/test/`, `tests/` | Simulated-host Java checks and host-free Python regressions |
97
+ | `scripts/` | Source builds/checks and offline evidence helpers |
98
+ | `examples/` | Client configuration and explicit opt-in music recipes |
99
+ | `docs/` | Public architecture, installation navigation and packaging guides |
100
+ | `packaging/aur/` | Local Arch recipe and synchronized `.SRCINFO` |
101
+ | `skills/bitwig-agent/` | Copyable Agent Skills instructions, focused references and MIT license |
102
+
103
+ The default-package `extension/src/main/java/BitwigAgent613GridInsertion.java` is intentional: its native superclass is also in the unnamed package and it is loaded by that exact class name. Historical evidence is not active test infrastructure; use [VERIFICATION.md](VERIFICATION.md) for current checks.