Add multi-platform release workflows for GitHub, NPM, and PyPI
- Replace single release.yml with platform-specific workflows: - release-github.yml for GitHub Releases and Homebrew tap updates - release-npm.yml for publishing binaries and base package to NPM - release-pypi.yml for building and publishing wheels/sdist to PyPI - Add Homebrew tap update automation - Add NPM packaging scripts, templates, and TypeScript base package - Add PyPI packaging with maturin and metadata - Add .nvmrc and rust-toolchain.toml for consistent builds - Update Cargo.toml with repository, homepage, keywords, categories, and authors
Seto Elkahfi committed
Apr 24, 2026 at 00:57 UTC
cd75bec906625ae4cac5c441a107846bfb360952
20 files changed
+1221
-171
.github/workflows/release-github.yml
new
+187
@@ -0,0 +1,187 @@
1
+name: GitHub Release
2
+
3
+on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: "Release tag (e.g. v0.1.1)"
11
+ required: true
12
+
13
+permissions:
14
+ contents: write
15
+ actions: write
16
+
17
+env:
18
+ PROJECT_NAME: sigit
19
+ CARGO_TERM_COLOR: always
20
+
21
+jobs:
22
+ build:
23
+ name: Build binary (${{ matrix.name }})
24
+ runs-on: ${{ matrix.runner }}
25
+
26
+ strategy:
27
+ fail-fast: false
28
+ matrix:
29
+ include:
30
+ - name: linux-amd64
31
+ runner: ubuntu-latest
32
+ target: x86_64-unknown-linux-gnu
33
+ - name: linux-arm64
34
+ runner: ubuntu-24.04-arm
35
+ target: aarch64-unknown-linux-gnu
36
+ - name: win-amd64
37
+ runner: windows-latest
38
+ target: x86_64-pc-windows-msvc
39
+ - name: win-arm64
40
+ runner: windows-latest
41
+ target: aarch64-pc-windows-msvc
42
+ - name: macos-amd64
43
+ runner: macos-15-intel
44
+ target: x86_64-apple-darwin
45
+ - name: macos-arm64
46
+ runner: macos-latest
47
+ target: aarch64-apple-darwin
48
+
49
+ steps:
50
+ - name: Checkout
51
+ uses: actions/checkout@v6
52
+ with:
53
+ ref: ${{ github.event.inputs.tag || github.ref }}
54
+
55
+ - name: Set the release version
56
+ shell: bash
57
+ run: |
58
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
59
+ release_version="${GITHUB_REF_NAME#v}"
60
+ else
61
+ release_version="${{ github.event.inputs.tag }}"
62
+ release_version="${release_version#v}"
63
+ fi
64
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
65
+
66
+ - name: Read Rust toolchain
67
+ shell: bash
68
+ run: |
69
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
70
+ if [ -z "$rust_toolchain" ]; then
71
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
72
+ exit 1
73
+ fi
74
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
75
+
76
+ - name: Install Rust toolchain
77
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
78
+ with:
79
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
80
+ targets: ${{ matrix.target }}
81
+
82
+ - name: Setup Rust cache
83
+ uses: Swatinem/rust-cache@v2
84
+ with:
85
+ key: github-${{ matrix.target }}
86
+
87
+ - name: Build binary
88
+ shell: bash
89
+ run: cargo build --locked --release --target ${{ matrix.target }}
90
+
91
+ - name: Package binary
92
+ shell: bash
93
+ run: |
94
+ BIN_SUFFIX=""
95
+ if [[ "${{ matrix.runner }}" == "windows-latest" ]]; then
96
+ BIN_SUFFIX=".exe"
97
+ fi
98
+
99
+ BIN_OUTPUT="target/${{ matrix.target }}/release/${PROJECT_NAME}${BIN_SUFFIX}"
100
+ BIN_RELEASE="${PROJECT_NAME}-${{ matrix.name }}${BIN_SUFFIX}"
101
+
102
+ mkdir -p ./release
103
+ mv "${BIN_OUTPUT}" "./release/${BIN_RELEASE}"
104
+
105
+ - name: Package macOS tarball for Homebrew
106
+ if: contains(matrix.target, 'apple-darwin')
107
+ shell: bash
108
+ run: |
109
+ ARCHIVE_NAME="${PROJECT_NAME}-${{ matrix.name }}.tar.gz"
110
+
111
+ mkdir -p staging-brew
112
+ cp "./release/${PROJECT_NAME}-${{ matrix.name }}" "staging-brew/${PROJECT_NAME}"
113
+ strip "staging-brew/${PROJECT_NAME}"
114
+
115
+ tar -C staging-brew -czf "${ARCHIVE_NAME}" "${PROJECT_NAME}"
116
+
117
+ shasum -a 256 "${ARCHIVE_NAME}" | awk '{print $1}' > "${ARCHIVE_NAME}.sha256"
118
+
119
+ echo "Archive: ${ARCHIVE_NAME}"
120
+ echo "SHA256: $(cat "${ARCHIVE_NAME}.sha256")"
121
+
122
+ - name: Upload binary artifact
123
+ uses: actions/upload-artifact@v4
124
+ with:
125
+ name: binary-${{ matrix.name }}
126
+ path: release/*
127
+
128
+ - name: Upload macOS Homebrew artifacts
129
+ if: contains(matrix.target, 'apple-darwin')
130
+ uses: actions/upload-artifact@v4
131
+ with:
132
+ name: homebrew-${{ matrix.name }}
133
+ path: |
134
+ ${{ env.PROJECT_NAME }}-${{ matrix.name }}.tar.gz
135
+ ${{ env.PROJECT_NAME }}-${{ matrix.name }}.tar.gz.sha256
136
+
137
+ release:
138
+ name: Create GitHub Release
139
+ needs: build
140
+ runs-on: ubuntu-latest
141
+ if: github.ref_type == 'tag' || github.event_name == 'workflow_dispatch'
142
+
143
+ steps:
144
+ - name: Resolve tag
145
+ id: tag
146
+ shell: bash
147
+ run: |
148
+ if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
149
+ echo "tag=${{ github.event.inputs.tag }}" >> "$GITHUB_OUTPUT"
150
+ else
151
+ echo "tag=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
152
+ fi
153
+
154
+ - name: Download binary artifacts
155
+ uses: actions/download-artifact@v4
156
+ with:
157
+ pattern: "binary-*"
158
+ path: release
159
+ merge-multiple: true
160
+
161
+ - name: Download Homebrew artifacts
162
+ uses: actions/download-artifact@v4
163
+ with:
164
+ pattern: "homebrew-*"
165
+ path: release
166
+ merge-multiple: true
167
+
168
+ - name: Release
169
+ uses: softprops/action-gh-release@v2
170
+ with:
171
+ tag_name: ${{ steps.tag.outputs.tag }}
172
+ files: release/*
173
+
174
+ - name: Trigger Homebrew release
175
+ uses: actions/github-script@v7
176
+ with:
177
+ script: |
178
+ await github.rest.actions.createWorkflowDispatch({
179
+ owner: context.repo.owner,
180
+ repo: context.repo.repo,
181
+ workflow_id: 'release-homebrew.yml',
182
+ ref: 'main',
183
+ inputs: {
184
+ tag: '${{ steps.tag.outputs.tag }}'
185
+ }
186
+ })
187
+ console.log('Dispatched release-homebrew.yml for tag ${{ steps.tag.outputs.tag }}')
.github/workflows/release-homebrew.yml
new
+116
@@ -0,0 +1,116 @@
1
+name: Homebrew CLI Release
2
+
3
+on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ tag:
7
+ description: "Release tag (e.g. v0.1.1)"
8
+ required: true
9
+
10
+permissions:
11
+ contents: read
12
+
13
+env:
14
+ REPO: getsigit/sigit
15
+
16
+jobs:
17
+ update-homebrew-tap:
18
+ name: Update Homebrew tap
19
+ runs-on: ubuntu-latest
20
+
21
+ steps:
22
+ - name: Resolve tag and version
23
+ id: release
24
+ shell: bash
25
+ run: |
26
+ TAG="${{ github.event.inputs.tag }}"
27
+ VERSION="${TAG#v}"
28
+
29
+ echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
30
+ echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
31
+
32
+ - name: Read SHA256 checksums from release
33
+ id: sha
34
+ env:
35
+ GH_TOKEN: ${{ github.token }}
36
+ shell: bash
37
+ run: |
38
+ mkdir -p artifacts
39
+
40
+ gh release download "${{ steps.release.outputs.tag }}" \
41
+ --repo "${{ env.REPO }}" \
42
+ --pattern "sigit-macos-*.tar.gz.sha256" \
43
+ --dir artifacts/
44
+
45
+ ARM64_SHA=$(cat artifacts/sigit-macos-arm64.tar.gz.sha256)
46
+ AMD64_SHA=$(cat artifacts/sigit-macos-amd64.tar.gz.sha256)
47
+
48
+ echo "arm64=${ARM64_SHA}" >> "$GITHUB_OUTPUT"
49
+ echo "amd64=${AMD64_SHA}" >> "$GITHUB_OUTPUT"
50
+
51
+ echo "ARM64 SHA256: ${ARM64_SHA}"
52
+ echo "AMD64 SHA256: ${AMD64_SHA}"
53
+
54
+ - name: Checkout Homebrew tap
55
+ uses: actions/checkout@v6
56
+ with:
57
+ repository: getsigit/sigit-homebrew-tap
58
+ token: ${{ secrets.HOMEBREW_TAP_TOKEN }}
59
+ path: homebrew-tap
60
+
61
+ - name: Generate formula
62
+ shell: bash
63
+ run: |
64
+ VERSION="${{ steps.release.outputs.version }}"
65
+ TAG="${{ steps.release.outputs.tag }}"
66
+ ARM64_SHA="${{ steps.sha.outputs.arm64 }}"
67
+ AMD64_SHA="${{ steps.sha.outputs.amd64 }}"
68
+
69
+ mkdir -p homebrew-tap/Formula
70
+
71
+ cat > homebrew-tap/Formula/sigit.rb <<FORMULA
72
+ # frozen_string_literal: true
73
+
74
+ # Homebrew formula for siGit Code (\`sigit\` binary).
75
+ class Sigit < Formula
76
+ desc 'AI coding agent powered by local LLM via Onde Inference'
77
+ homepage 'https://github.com/getsigit/sigit'
78
+ version '${VERSION}'
79
+ license 'Apache-2.0'
80
+
81
+ on_macos do
82
+ on_arm do
83
+ url 'https://github.com/${REPO}/releases/download/${TAG}/sigit-macos-arm64.tar.gz'
84
+ sha256 '${ARM64_SHA}'
85
+ end
86
+ on_intel do
87
+ url 'https://github.com/${REPO}/releases/download/${TAG}/sigit-macos-amd64.tar.gz'
88
+ sha256 '${AMD64_SHA}'
89
+ end
90
+ end
91
+
92
+ def install
93
+ bin.install 'sigit'
94
+ end
95
+
96
+ test do
97
+ assert_match version.to_s, shell_output("#{bin}/sigit --version", 1)
98
+ end
99
+ end
100
+ FORMULA
101
+
102
+ echo "Generated formula:"
103
+ cat homebrew-tap/Formula/sigit.rb
104
+
105
+ - name: Commit and push
106
+ shell: bash
107
+ run: |
108
+ VERSION="${{ steps.release.outputs.version }}"
109
+
110
+ cd homebrew-tap
111
+ git config user.name "github-actions[bot]"
112
+ git config user.email "github-actions[bot]@users.noreply.github.com"
113
+ git add Formula/sigit.rb
114
+ git diff --cached --quiet && echo "No changes to commit" && exit 0
115
+ git commit -m "Update sigit to ${VERSION}"
116
+ git push
.github/workflows/release-npm.yml
new
+220
@@ -0,0 +1,220 @@
1
+name: NPM Release
2
+
3
+on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: "Release tag (e.g. v0.1.1)"
11
+ required: true
12
+
13
+permissions:
14
+ id-token: write
15
+ contents: read
16
+
17
+env:
18
+ CARGO_TERM_COLOR: always
19
+
20
+jobs:
21
+ publish-npm-binaries:
22
+ name: Publish NPM platform packages
23
+ runs-on: ${{ matrix.build.OS }}
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ build:
28
+ - {
29
+ NAME: linux-x64-glibc,
30
+ OS: ubuntu-latest,
31
+ TARGET: x86_64-unknown-linux-gnu,
32
+ }
33
+ - {
34
+ NAME: linux-arm64-glibc,
35
+ OS: ubuntu-24.04-arm,
36
+ TARGET: aarch64-unknown-linux-gnu,
37
+ }
38
+ - {
39
+ NAME: win32-x64-msvc,
40
+ OS: windows-2022,
41
+ TARGET: x86_64-pc-windows-msvc,
42
+ }
43
+ - {
44
+ NAME: win32-arm64-msvc,
45
+ OS: windows-2022,
46
+ TARGET: aarch64-pc-windows-msvc,
47
+ }
48
+ - {
49
+ NAME: darwin-x64,
50
+ OS: macos-15-intel,
51
+ TARGET: x86_64-apple-darwin,
52
+ }
53
+ - {
54
+ NAME: darwin-arm64,
55
+ OS: macos-latest,
56
+ TARGET: aarch64-apple-darwin,
57
+ }
58
+
59
+ steps:
60
+ - name: Checkout
61
+ uses: actions/checkout@v6
62
+ with:
63
+ ref: ${{ github.event.inputs.tag || github.ref }}
64
+
65
+ - name: Set the release version
66
+ shell: bash
67
+ run: |
68
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
69
+ release_version="${GITHUB_REF_NAME#v}"
70
+ else
71
+ release_version="${{ github.event.inputs.tag }}"
72
+ release_version="${release_version#v}"
73
+ fi
74
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
75
+
76
+ - name: Read Rust toolchain
77
+ shell: bash
78
+ run: |
79
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
80
+ if [ -z "$rust_toolchain" ]; then
81
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
82
+ exit 1
83
+ fi
84
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
85
+
86
+ - name: Install Rust toolchain
87
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
88
+ with:
89
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
90
+
91
+ - name: Install Rust target
92
+ shell: bash
93
+ run: |
94
+ rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
95
+ rustup target list --installed
96
+
97
+ - name: Setup Rust cache
98
+ uses: Swatinem/rust-cache@v2
99
+ with:
100
+ key: npm-${{ matrix.build.TARGET }}
101
+
102
+ - name: Build binary
103
+ shell: bash
104
+ run: cargo build --locked --release --target ${{ matrix.build.TARGET }}
105
+
106
+ - name: Install Node
107
+ uses: actions/setup-node@v6
108
+ with:
109
+ node-version-file: .nvmrc
110
+ registry-url: "https://registry.npmjs.org"
111
+
112
+ - name: Publish platform package to NPM
113
+ env:
114
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
115
+ shell: bash
116
+ run: |
117
+ cd npm
118
+
119
+ # Binary name from Cargo.toml
120
+ cargo_bin="sigit"
121
+
122
+ # Prefix used for optional dependency package names
123
+ node_pkg_prefix="sigit"
124
+
125
+ # Derive OS and architecture from the build matrix name
126
+ # Matrix name format: <os>-<arch>[-<extra>]
127
+ node_os=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f1)
128
+ export node_os
129
+ node_arch=$(echo "${{ matrix.build.NAME }}" | cut -d '-' -f2)
130
+ export node_arch
131
+
132
+ # Set the version
133
+ export node_version="${{ env.RELEASE_VERSION }}"
134
+
135
+ # Build the platform package name; normalise win32 → windows
136
+ if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
137
+ export node_pkg="${node_pkg_prefix}-windows-${node_arch}"
138
+ else
139
+ export node_pkg="${node_pkg_prefix}-${node_os}-${node_arch}"
140
+ fi
141
+
142
+ # Create the package directory
143
+ mkdir -p "${node_pkg}/bin"
144
+
145
+ # Generate package.json + README for this platform slice
146
+ node ./scripts/render-platform-package.cjs \
147
+ "${node_pkg}" \
148
+ "${node_version}" \
149
+ "${node_os}" \
150
+ "${node_arch}"
151
+
152
+ # Windows binaries carry a .exe extension
153
+ if [ "${{ matrix.build.OS }}" = "windows-2022" ]; then
154
+ cargo_bin="${cargo_bin}.exe"
155
+ fi
156
+
157
+ cp "../target/${{ matrix.build.TARGET }}/release/${cargo_bin}" "${node_pkg}/bin"
158
+
159
+ cd "${node_pkg}"
160
+
161
+ npm_package_name="@smbcloud/${node_pkg}"
162
+ if npm view "${npm_package_name}@${node_version}" version >/dev/null 2>&1; then
163
+ echo "${npm_package_name}@${node_version} already exists on npm, skipping publish"
164
+ exit 0
165
+ fi
166
+
167
+ npm publish --access public --provenance
168
+
169
+ publish-npm-base:
170
+ name: Publish base NPM package (@smbcloud/sigit)
171
+ needs: publish-npm-binaries
172
+ runs-on: ubuntu-latest
173
+
174
+ steps:
175
+ - name: Checkout
176
+ uses: actions/checkout@v6
177
+ with:
178
+ ref: ${{ github.event.inputs.tag || github.ref }}
179
+
180
+ - name: Set the release version
181
+ shell: bash
182
+ run: |
183
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
184
+ release_version="${GITHUB_REF_NAME#v}"
185
+ else
186
+ release_version="${{ github.event.inputs.tag }}"
187
+ release_version="${release_version#v}"
188
+ fi
189
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
190
+
191
+ - name: Install Node
192
+ uses: actions/setup-node@v6
193
+ with:
194
+ node-version-file: .nvmrc
195
+ registry-url: "https://registry.npmjs.org"
196
+
197
+ - name: Publish base package to NPM
198
+ env:
199
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
200
+ shell: bash
201
+ run: |
202
+ cd npm/sigit
203
+
204
+ # Rewrite package.json with the correct release version and
205
+ # matching optionalDependency versions
206
+ node ../scripts/render-main-package.cjs \
207
+ "./package.json" \
208
+ "${{ env.RELEASE_VERSION }}"
209
+
210
+ npm_package_name="@smbcloud/sigit"
211
+ npm_package_version="${{ env.RELEASE_VERSION }}"
212
+
213
+ if npm view "${npm_package_name}@${npm_package_version}" version >/dev/null 2>&1; then
214
+ echo "${npm_package_name}@${npm_package_version} already exists on npm, skipping publish"
215
+ exit 0
216
+ fi
217
+
218
+ npm install
219
+ npm run build
220
+ npm publish --access public --provenance
.github/workflows/release-pypi.yml
new
+191
@@ -0,0 +1,191 @@
1
+name: PyPI Release
2
+
3
+on:
4
+ push:
5
+ tags:
6
+ - "v*.*.*"
7
+ workflow_dispatch:
8
+ inputs:
9
+ tag:
10
+ description: "Release tag (e.g. v0.1.1)"
11
+ required: true
12
+
13
+permissions:
14
+ id-token: write
15
+ contents: read
16
+
17
+env:
18
+ CARGO_TERM_COLOR: always
19
+
20
+jobs:
21
+ build-wheels:
22
+ name: Build PyPI wheels
23
+ runs-on: ${{ matrix.build.OS }}
24
+ strategy:
25
+ fail-fast: false
26
+ matrix:
27
+ build:
28
+ - {
29
+ NAME: linux-x64-glibc,
30
+ OS: ubuntu-latest,
31
+ TARGET: x86_64-unknown-linux-gnu,
32
+ MANYLINUX: "2014",
33
+ }
34
+ - {
35
+ NAME: linux-arm64-glibc,
36
+ OS: ubuntu-24.04-arm,
37
+ TARGET: aarch64-unknown-linux-gnu,
38
+ MANYLINUX: "2014",
39
+ }
40
+ - {
41
+ NAME: win32-x64-msvc,
42
+ OS: windows-2022,
43
+ TARGET: x86_64-pc-windows-msvc,
44
+ }
45
+ - {
46
+ NAME: win32-arm64-msvc,
47
+ OS: windows-2022,
48
+ TARGET: aarch64-pc-windows-msvc,
49
+ }
50
+ - { NAME: darwin-x64, OS: macos-latest, TARGET: x86_64-apple-darwin }
51
+ - {
52
+ NAME: darwin-arm64,
53
+ OS: macos-latest,
54
+ TARGET: aarch64-apple-darwin,
55
+ }
56
+ steps:
57
+ - name: Checkout
58
+ uses: actions/checkout@v6
59
+ with:
60
+ ref: ${{ github.event.inputs.tag || github.ref }}
61
+
62
+ - name: Set the release version
63
+ shell: bash
64
+ run: |
65
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
66
+ release_version="${GITHUB_REF_NAME#v}"
67
+ else
68
+ release_version="${{ github.event.inputs.tag }}"
69
+ release_version="${release_version#v}"
70
+ fi
71
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
72
+
73
+ - name: Read Rust toolchain
74
+ shell: bash
75
+ run: |
76
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
77
+ if [ -z "$rust_toolchain" ]; then
78
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
79
+ exit 1
80
+ fi
81
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
82
+
83
+ - name: Install Rust toolchain
84
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
85
+ with:
86
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
87
+
88
+ - name: Install Rust target
89
+ shell: bash
90
+ run: |
91
+ rustup target add ${{ matrix.build.TARGET }} --toolchain ${{ env.RUST_TOOLCHAIN }}
92
+ rustup target list --installed
93
+
94
+ - name: Build wheel
95
+ uses: PyO3/maturin-action@v1
96
+ with:
97
+ target: ${{ matrix.build.TARGET }}
98
+ manylinux: ${{ matrix.build.MANYLINUX || 'off' }}
99
+ working-directory: pypi
100
+ args: --release --locked --compatibility pypi --out dist
101
+ before-script-linux: yum install -y perl-core
102
+
103
+ - name: Upload wheel artifact
104
+ uses: actions/upload-artifact@v4
105
+ with:
106
+ name: wheels-${{ matrix.build.NAME }}
107
+ path: pypi/dist/*
108
+
109
+ build-sdist:
110
+ name: Build source distribution
111
+ runs-on: ubuntu-latest
112
+ steps:
113
+ - name: Checkout
114
+ uses: actions/checkout@v6
115
+ with:
116
+ ref: ${{ github.event.inputs.tag || github.ref }}
117
+
118
+ - name: Read Rust toolchain
119
+ shell: bash
120
+ run: |
121
+ rust_toolchain="$(sed -n 's/^channel = "\(.*\)"/\1/p' rust-toolchain.toml | head -n 1)"
122
+ if [ -z "$rust_toolchain" ]; then
123
+ echo "Failed to read Rust toolchain from rust-toolchain.toml" >&2
124
+ exit 1
125
+ fi
126
+ echo "RUST_TOOLCHAIN=${rust_toolchain}" >> "$GITHUB_ENV"
127
+
128
+ - name: Install Rust toolchain
129
+ uses: dtolnay/rust-toolchain@3c5f7ea28cd621ae0bf5283f0e981fb97b8a7af9
130
+ with:
131
+ toolchain: ${{ env.RUST_TOOLCHAIN }}
132
+
133
+ - name: Build sdist
134
+ uses: PyO3/maturin-action@v1
135
+ with:
136
+ command: sdist
137
+ working-directory: pypi
138
+ args: --out dist
139
+
140
+ - name: Upload sdist artifact
141
+ uses: actions/upload-artifact@v4
142
+ with:
143
+ name: sdist
144
+ path: pypi/dist/*
145
+
146
+ publish-pypi:
147
+ name: Publish to PyPI
148
+ runs-on: ubuntu-latest
149
+ needs:
150
+ - build-wheels
151
+ - build-sdist
152
+ steps:
153
+ - name: Checkout
154
+ uses: actions/checkout@v6
155
+ with:
156
+ ref: ${{ github.event.inputs.tag || github.ref }}
157
+
158
+ - name: Set the release version
159
+ shell: bash
160
+ run: |
161
+ if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
162
+ release_version="${GITHUB_REF_NAME#v}"
163
+ else
164
+ release_version="${{ github.event.inputs.tag }}"
165
+ release_version="${release_version#v}"
166
+ fi
167
+ echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
168
+
169
+ - name: Download distribution artifacts
170
+ uses: actions/download-artifact@v4
171
+ with:
172
+ pattern: "*"
173
+ path: dist
174
+ merge-multiple: true
175
+
176
+ - name: Check whether release already exists on PyPI
177
+ id: pypi-check
178
+ shell: bash
179
+ run: |
180
+ if curl -fsS "https://pypi.org/pypi/sigit-code/${RELEASE_VERSION}/json" >/dev/null 2>&1; then
181
+ echo "sigit-code ${RELEASE_VERSION} already exists on PyPI, skipping publish"
182
+ echo "exists=true" >> "$GITHUB_OUTPUT"
183
+ else
184
+ echo "exists=false" >> "$GITHUB_OUTPUT"
185
+ fi
186
+
187
+ - name: Publish distribution
188
+ if: steps.pypi-check.outputs.exists != 'true'
189
+ uses: pypa/gh-action-pypi-publish@release/v1
190
+ with:
191
+ skip-existing: true
.github/workflows/release.yml
deleted
-171
@@ -1,171 +0,0 @@
1
-name: Release
2
-
3
-on:
4
- push:
5
- tags:
6
- - "v*.*.*"
7
- workflow_dispatch:
8
- inputs:
9
- tag:
10
- description: "Release tag (e.g. v0.1.0)"
11
- required: true
12
-
13
-permissions:
14
- contents: write
15
-
16
-env:
17
- CARGO_TERM_COLOR: always
18
-
19
-jobs:
20
- build:
21
- name: Build ${{ matrix.artifact }}
22
- runs-on: ${{ matrix.os }}
23
- strategy:
24
- fail-fast: false
25
- matrix:
26
- include:
27
- - target: aarch64-apple-darwin
28
- os: macos-26
29
- artifact: sigit-darwin-aarch64
30
- binary: sigit
31
- archive_ext: tar.gz
32
-
33
- - target: x86_64-apple-darwin
34
- os: macos-26-intel
35
- artifact: sigit-darwin-x86_64
36
- binary: sigit
37
- archive_ext: tar.gz
38
-
39
- steps:
40
- - name: Checkout
41
- uses: actions/checkout@v6
42
- with:
43
- ref: ${{ github.event.inputs.tag || github.ref }}
44
-
45
- - name: Set release version
46
- shell: bash
47
- run: |
48
- if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
49
- release_version="${GITHUB_REF_NAME#v}"
50
- else
51
- release_version="${{ github.event.inputs.tag }}"
52
- release_version="${release_version#v}"
53
- fi
54
-
55
- echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
56
-
57
- - name: Verify Cargo.toml version matches tag
58
- shell: bash
59
- run: |
60
- CARGO_VERSION=$(cargo metadata --no-deps --format-version 1 \
61
- | jq -r '.packages[] | select(.name == "sigit") | .version')
62
-
63
- echo "Cargo.toml version : ${CARGO_VERSION}"
64
- echo "Release tag version: ${RELEASE_VERSION}"
65
-
66
- if [[ "${CARGO_VERSION}" != "${RELEASE_VERSION}" ]]; then
67
- echo "::error::Version mismatch — bump Cargo.toml version before tagging."
68
- exit 1
69
- fi
70
-
71
- - name: Install Rust toolchain
72
- uses: dtolnay/rust-toolchain@stable
73
- with:
74
- targets: ${{ matrix.target }}
75
-
76
- - name: Setup Rust cache
77
- uses: Swatinem/rust-cache@v2
78
- with:
79
- key: release-${{ matrix.target }}
80
-
81
- - name: Build
82
- shell: bash
83
- run: cargo build --release --locked --target ${{ matrix.target }}
84
-
85
- - name: Package (tar.gz)
86
- if: matrix.archive_ext == 'tar.gz'
87
- shell: bash
88
- run: |
89
- binary="target/${{ matrix.target }}/release/${{ matrix.binary }}"
90
- archive="${{ matrix.artifact }}.tar.gz"
91
-
92
- tar -czf "${archive}" -C "$(dirname "${binary}")" "${{ matrix.binary }}"
93
-
94
- echo "ARCHIVE=${archive}" >> "$GITHUB_ENV"
95
-
96
- - name: Package (zip)
97
- if: matrix.archive_ext == 'zip'
98
- shell: pwsh
99
- run: |
100
- $binary = "target\${{ matrix.target }}\release\${{ matrix.binary }}"
101
- $archive = "${{ matrix.artifact }}.zip"
102
-
103
- Compress-Archive -Path $binary -DestinationPath $archive
104
-
105
- "ARCHIVE=$archive" | Out-File -FilePath $env:GITHUB_ENV -Append
106
-
107
- - name: Upload archive
108
- uses: actions/upload-artifact@v4
109
- with:
110
- name: ${{ matrix.artifact }}
111
- path: ${{ env.ARCHIVE }}
112
- if-no-files-found: error
113
- retention-days: 1
114
-
115
- release:
116
- name: Publish GitHub Release
117
- needs: build
118
- runs-on: ubuntu-latest
119
- permissions:
120
- contents: write
121
-
122
- steps:
123
- - name: Checkout
124
- uses: actions/checkout@v6
125
- with:
126
- ref: ${{ github.event.inputs.tag || github.ref }}
127
-
128
- - name: Set release version and tag
129
- shell: bash
130
- run: |
131
- if [[ "${GITHUB_REF_TYPE}" == "tag" ]]; then
132
- release_tag="${GITHUB_REF_NAME}"
133
- release_version="${GITHUB_REF_NAME#v}"
134
- else
135
- release_tag="${{ github.event.inputs.tag }}"
136
- release_version="${{ github.event.inputs.tag }}"
137
- release_version="${release_version#v}"
138
- fi
139
-
140
- echo "RELEASE_TAG=${release_tag}" >> "$GITHUB_ENV"
141
- echo "RELEASE_VERSION=${release_version}" >> "$GITHUB_ENV"
142
-
143
- - name: Download all archives
144
- uses: actions/download-artifact@v4
145
- with:
146
- path: archives
147
- merge-multiple: true
148
-
149
- - name: Check whether release already exists
150
- id: release-check
151
- shell: bash
152
- run: |
153
- if gh release view "${RELEASE_TAG}" --repo "${{ github.repository }}" >/dev/null 2>&1; then
154
- echo "Release ${RELEASE_TAG} already exists — skipping."
155
- echo "exists=true" >> "$GITHUB_OUTPUT"
156
- else
157
- echo "exists=false" >> "$GITHUB_OUTPUT"
158
- fi
159
- env:
160
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
161
-
162
- - name: Create release and upload archives
163
- if: steps.release-check.outputs.exists != 'true'
164
- shell: bash
165
- run: |
166
- gh release create "${RELEASE_TAG}" \
167
- --title "siGit ${RELEASE_TAG}" \
168
- --generate-notes \
169
- archives/*
170
- env:
171
- GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
.nvmrc
new
+1
@@ -0,0 +1 @@
1
+20
Cargo.toml
+6
@@ -5,6 +5,12 @@ edition = "2024"
5
description = "siGit Code — ACP-compatible AI coding agent for smbCloud platform."
6
documentation = "https://github.com/getsigit/sigit"
7
license = "Apache-2.0"
8
+repository = "https://github.com/getsigit/sigit"
9
+homepage = "https://smbcloud.xyz"
10
+readme = "README.md"
11
+keywords = ["sigit", "cli", "ai", "coding-agent", "llm"]
12
+categories = ["command-line-utilities"]
13
+authors = ["Seto Elkahfi <hej@setoelkahfi.se>"]
14
15
[[bin]]
16
name = "sigit"
npm/README.md.tmpl
new
+22
@@ -0,0 +1,22 @@
1
+<h1 align="center">siGit Code</h1>
2
+
3
+## `${node_pkg}`
4
+
5
+This is a platform-specific binary for [`@smbcloud/sigit`](https://www.npmjs.com/package/@smbcloud/sigit). You don't need to install it directly.
6
+
7
+Install the main package instead:
8
+
9
+```sh
10
+npm install -g @smbcloud/sigit
11
+```
12
+
13
+npm pulls in the right binary for your OS and architecture.
14
+
15
+## Links
16
+
17
+- [Source code](https://github.com/getsigit/sigit)
18
+- [Issues](https://github.com/getsigit/sigit/issues)
19
+
20
+## License
21
+
22
+[Apache-2.0](https://github.com/getsigit/sigit/blob/main/LICENSE)
npm/package-main.json.tmpl
new
+41
@@ -0,0 +1,41 @@
1
+{
2
+ "name": "@smbcloud/sigit",
3
+ "version": "${release_version}",
4
+ "keywords": [
5
+ "sigit",
6
+ "cli",
7
+ "ai",
8
+ "coding-agent",
9
+ "llm",
10
+ "on-device",
11
+ "smbcloud",
12
+ "acp"
13
+ ],
14
+ "bin": {
15
+ "sigit": "lib/index.js"
16
+ },
17
+ "files": ["lib", "README.md"],
18
+ "description": "AI coding agent powered by local LLM via Onde Inference.",
19
+ "license": "Apache-2.0",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/getsigit/sigit.git"
23
+ },
24
+ "scripts": {
25
+ "typecheck": "tsc --noEmit",
26
+ "build": "tsc",
27
+ "dev": "npm run build && node lib/index.js"
28
+ },
29
+ "devDependencies": {
30
+ "@types/node": "^18.15.11",
31
+ "typescript": "^5.0.0"
32
+ },
33
+ "optionalDependencies": {
34
+ "@smbcloud/sigit-darwin-arm64": "${release_version}",
35
+ "@smbcloud/sigit-darwin-x64": "${release_version}",
36
+ "@smbcloud/sigit-linux-arm64": "${release_version}",
37
+ "@smbcloud/sigit-linux-x64": "${release_version}",
38
+ "@smbcloud/sigit-windows-arm64": "${release_version}",
39
+ "@smbcloud/sigit-windows-x64": "${release_version}"
40
+ }
41
+}
npm/package.json.tmpl
new
+14
@@ -0,0 +1,14 @@
1
+{
2
+ "name": "@smbcloud/${node_pkg}",
3
+ "version": "${node_version}",
4
+ "description": "Platform binary for siGit Code.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/getsigit/sigit.git"
9
+ },
10
+ "keywords": ["${node_pkg}","cli","binary","sigit","ai","coding-agent"],
11
+ "os": ["${node_os}"],
12
+ "cpu": ["${node_arch}"],
13
+ "files": ["bin"]
14
+}
npm/scripts/render-main-package.cjs
new
+34
@@ -0,0 +1,34 @@
1
+#!/usr/bin/env node
2
+
3
+const fs = require("fs");
4
+const path = require("path");
5
+
6
+const [outputPath, version] = process.argv.slice(2);
7
+
8
+if (!outputPath || !version) {
9
+ throw new Error("Usage: render-main-package.cjs <output-path> <version>");
10
+}
11
+
12
+const npmRoot = path.resolve(__dirname, "..");
13
+
14
+const vars = {
15
+ release_version: version,
16
+};
17
+
18
+/**
19
+ * Replace every `${key}` in the template with the corresponding value from vars.
20
+ */
21
+function interpolate(template, variables) {
22
+ return template.replace(/\$\{(\w+)\}/g, (match, key) => {
23
+ if (key in variables) return variables[key];
24
+ return match;
25
+ });
26
+}
27
+
28
+// Read and interpolate package-main.json.tmpl
29
+const template = fs.readFileSync(
30
+ path.join(npmRoot, "package-main.json.tmpl"),
31
+ "utf-8",
32
+);
33
+
34
+fs.writeFileSync(path.resolve(outputPath), interpolate(template, vars));
npm/scripts/render-platform-package.cjs
new
+56
@@ -0,0 +1,56 @@
1
+#!/usr/bin/env node
2
+
3
+const fs = require("fs");
4
+const path = require("path");
5
+
6
+const [packageName, version, operatingSystem, architecture] =
7
+ process.argv.slice(2);
8
+
9
+if (!packageName || !version || !operatingSystem || !architecture) {
10
+ throw new Error(
11
+ "Usage: render-platform-package.cjs <package-name> <version> <os> <arch>",
12
+ );
13
+}
14
+
15
+const npmRoot = path.resolve(__dirname, "..");
16
+const packageDirectory = path.resolve(npmRoot, packageName);
17
+
18
+fs.mkdirSync(packageDirectory, { recursive: true });
19
+
20
+// Variable map for template interpolation
21
+const vars = {
22
+ node_pkg: packageName,
23
+ node_version: version,
24
+ node_os: operatingSystem,
25
+ node_arch: architecture,
26
+};
27
+
28
+/**
29
+ * Replace every `${key}` in the template with the corresponding value from vars.
30
+ */
31
+function interpolate(template, variables) {
32
+ return template.replace(/\$\{(\w+)\}/g, (match, key) => {
33
+ if (key in variables) return variables[key];
34
+ return match;
35
+ });
36
+}
37
+
38
+// Read and interpolate package.json.tmpl
39
+const packageTemplate = fs.readFileSync(
40
+ path.join(npmRoot, "package.json.tmpl"),
41
+ "utf-8",
42
+);
43
+fs.writeFileSync(
44
+ path.join(packageDirectory, "package.json"),
45
+ interpolate(packageTemplate, vars),
46
+);
47
+
48
+// Read and interpolate README.md.tmpl
49
+const readmeTemplate = fs.readFileSync(
50
+ path.join(npmRoot, "README.md.tmpl"),
51
+ "utf-8",
52
+);
53
+fs.writeFileSync(
54
+ path.join(packageDirectory, "README.md"),
55
+ interpolate(readmeTemplate, vars),
56
+);
npm/sigit/.gitignore
new
+2
@@ -0,0 +1,2 @@
1
+lib/
2
+node_modules/
npm/sigit/README.md
new
+85
@@ -0,0 +1,85 @@
1
+<h1 align="center">siGit Code</h1>
2
+
3
+<p align="center">
4
+ AI coding agent powered by local LLM via Onde Inference.
5
+</p>
6
+
7
+<p align="center">
8
+ <a href="https://www.npmjs.com/package/@smbcloud/sigit"><img src="https://img.shields.io/npm/v/@smbcloud/sigit?style=flat-square&labelColor=17211D&color=235843" alt="npm"></a>
9
+ <a href="https://crates.io/crates/sigit"><img src="https://img.shields.io/crates/v/sigit?style=flat-square&labelColor=17211D&color=235843" alt="crates.io"></a>
10
+ <a href="https://pypi.org/project/sigit/"><img src="https://img.shields.io/pypi/v/sigit?style=flat-square&labelColor=17211D&color=235843" alt="PyPI"></a>
11
+</p>
12
+
13
+---
14
+
15
+## Install
16
+
17
+```sh
18
+npm install -g @smbcloud/sigit
19
+```
20
+
21
+The right binary for your platform gets pulled in automatically. Works on macOS (Apple Silicon and Intel), Linux (x64 and arm64), and Windows (x64 and arm64).
22
+
23
+### Other ways to install
24
+
25
+| Method | Command |
26
+|---|---|
27
+| **Homebrew** | `brew install getsigit/homebrew-tap/sigit` |
28
+| **pip** | `pip install sigit` |
29
+| **Cargo** | `cargo install sigit` |
30
+
31
+---
32
+
33
+## Usage
34
+
35
+```sh
36
+sigit
37
+```
38
+
39
+Opens a TUI coding agent that runs entirely on your device using a local LLM.
40
+
41
+### Zed ACP (Agent Control Protocol)
42
+
43
+Add siGit as an agent in Zed by adding this to your settings:
44
+
45
+```json
46
+{
47
+ "agent": {
48
+ "profiles": {
49
+ "sigit": {
50
+ "provider": "acp",
51
+ "binary": "sigit",
52
+ "args": ["--acp"]
53
+ }
54
+ }
55
+ }
56
+}
57
+```
58
+
59
+---
60
+
61
+## Platform support
62
+
63
+| Platform | Architecture | Package |
64
+|---|---|---|
65
+| macOS | Apple Silicon (arm64) | `@smbcloud/sigit-darwin-arm64` |
66
+| macOS | Intel (x64) | `@smbcloud/sigit-darwin-x64` |
67
+| Linux | x64 | `@smbcloud/sigit-linux-x64` |
68
+| Linux | arm64 | `@smbcloud/sigit-linux-arm64` |
69
+| Windows | x64 | `@smbcloud/sigit-windows-x64` |
70
+| Windows | arm64 | `@smbcloud/sigit-windows-arm64` |
71
+
72
+---
73
+
74
+## Links
75
+
76
+- [Source code](https://github.com/getsigit/sigit)
77
+- [Issues](https://github.com/getsigit/sigit/issues)
78
+
79
+## License
80
+
81
+[Apache-2.0](https://github.com/getsigit/sigit/blob/main/LICENSE)
82
+
83
+<p align="center">
84
+ <sub>© 2026 <a href="https://www.smbcloud.xyz">smbCloud</a> · <a href="https://apps.apple.com/se/developer/splitfire-ab/id1831430993">Splitfire AB</a></sub>
85
+</p>
\ No newline at end of file
npm/sigit/package.json
new
+44
@@ -0,0 +1,44 @@
1
+{
2
+ "name": "@smbcloud/sigit",
3
+ "version": "0.0.0-dev",
4
+ "keywords": [
5
+ "sigit",
6
+ "cli",
7
+ "ai",
8
+ "coding-agent",
9
+ "llm",
10
+ "on-device",
11
+ "smbcloud",
12
+ "acp"
13
+ ],
14
+ "bin": {
15
+ "sigit": "lib/index.js"
16
+ },
17
+ "files": [
18
+ "lib",
19
+ "README.md"
20
+ ],
21
+ "description": "AI coding agent powered by local LLM via Onde Inference.",
22
+ "license": "Apache-2.0",
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/getsigit/sigit.git"
26
+ },
27
+ "scripts": {
28
+ "typecheck": "tsc --noEmit",
29
+ "build": "tsc",
30
+ "dev": "npm run build && node lib/index.js"
31
+ },
32
+ "devDependencies": {
33
+ "@types/node": "^18.15.11",
34
+ "typescript": "^5.0.0"
35
+ },
36
+ "optionalDependencies": {
37
+ "@smbcloud/sigit-darwin-arm64": "0.0.0-dev",
38
+ "@smbcloud/sigit-darwin-x64": "0.0.0-dev",
39
+ "@smbcloud/sigit-linux-arm64": "0.0.0-dev",
40
+ "@smbcloud/sigit-linux-x64": "0.0.0-dev",
41
+ "@smbcloud/sigit-windows-arm64": "0.0.0-dev",
42
+ "@smbcloud/sigit-windows-x64": "0.0.0-dev"
43
+ }
44
+}
npm/sigit/src/index.ts
new
+43
@@ -0,0 +1,43 @@
1
+#!/usr/bin/env node
2
+
3
+import { spawnSync } from "child_process";
4
+
5
+/**
6
+ * Returns the executable path which is located inside node_modules
7
+ * The naming convention is cli-OS-ARCH
8
+ * If the platform is win32 or cygwin, executable will include a .exe extension.
9
+ * @see https://nodejs.org/api/os.html#osarch
10
+ * @see https://nodejs.org/api/os.html#osplatform
11
+ * @example "x/xx/node_modules/cli-darwin-arm64"
12
+ */
13
+function getExePath() {
14
+ const arch = process.arch;
15
+ let os = process.platform as string;
16
+ let extension = "";
17
+ if (["win32", "cygwin"].includes(process.platform)) {
18
+ os = "windows";
19
+ extension = ".exe";
20
+ }
21
+
22
+ try {
23
+ // Since the binary will be located inside node_modules, we can simply call require.resolve
24
+ return require.resolve(
25
+ `@smbcloud/sigit-${os}-${arch}/bin/sigit${extension}`,
26
+ );
27
+ } catch (e) {
28
+ throw new Error(
29
+ `Couldn't find application binary inside node_modules for ${os}-${arch}`,
30
+ );
31
+ }
32
+}
33
+
34
+/**
35
+ * Runs the application with args using nodejs spawn
36
+ */
37
+function run() {
38
+ const args = process.argv.slice(2);
39
+ const processResult = spawnSync(getExePath(), args, { stdio: "inherit" });
40
+ process.exit(processResult.status ?? 0);
41
+}
42
+
43
+run();
npm/sigit/tsconfig.json
new
+12
@@ -0,0 +1,12 @@
1
+{
2
+ "compilerOptions": {
3
+ "target": "es2016",
4
+ "module": "commonjs",
5
+ "esModuleInterop": true,
6
+ "baseUrl": "./",
7
+ "outDir": "lib",
8
+ "forceConsistentCasingInFileNames": true,
9
+ "strict": true,
10
+ "skipLibCheck": true
11
+ }
12
+}
pypi/README.md
new
+107
@@ -0,0 +1,107 @@
1
+<p align="center">
2
+ <strong>siGit Code</strong>
3
+</p>
4
+
5
+<h1 align="center">sigit</h1>
6
+
7
+<p align="center">
8
+ <strong>AI coding agent powered by local LLM via <a href="https://ondeinference.com">Onde Inference</a>.</strong><br>
9
+ ACP-compatible agent that runs entirely on your machine — no API keys, no cloud.
10
+</p>
11
+
12
+<p align="center">
13
+ <a href="https://smbcloud.xyz"><img src="https://img.shields.io/badge/smbcloud.xyz-235843?style=flat-square&labelColor=17211D" alt="Website"></a>
14
+ <a href="https://pypi.org/project/sigit-code/"><img src="https://img.shields.io/pypi/v/sigit-code?style=flat-square&labelColor=17211D&color=235843" alt="PyPI"></a>
15
+ <a href="https://www.npmjs.com/package/@smbcloud/sigit"><img src="https://img.shields.io/npm/v/@smbcloud/sigit?style=flat-square&labelColor=17211D&color=235843" alt="npm"></a>
16
+ <a href="https://crates.io/crates/sigit"><img src="https://img.shields.io/crates/v/sigit?style=flat-square&labelColor=17211D&color=235843" alt="Crates.io"></a>
17
+ <a href="https://github.com/getsigit/sigit/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-235843?style=flat-square&labelColor=17211D" alt="License"></a>
18
+</p>
19
+
20
+<br>
21
+
22
+---
23
+
24
+## Install
25
+
26
+```sh
27
+pip install sigit-code
28
+```
29
+
30
+Installs the native `sigit` binary for your platform — no compiler, no Node.js, no runtime dependencies.
31
+
32
+## Quick start
33
+
34
+### Interactive TUI
35
+
36
+```sh
37
+sigit
38
+```
39
+
40
+A terminal UI opens where you can chat with a local LLM coding agent directly.
41
+
42
+### Zed editor (ACP agent)
43
+
44
+siGit works as an [ACP-compatible](https://github.com/nicobailon/agent-client-protocol) agent in [Zed](https://zed.dev). Add this to your Zed settings:
45
+
46
+```json
47
+{
48
+ "agent": {
49
+ "profiles": {
50
+ "sigit": {
51
+ "provider": "acp",
52
+ "binary": {
53
+ "path": "sigit",
54
+ "args": ["--acp"]
55
+ }
56
+ }
57
+ }
58
+ }
59
+}
60
+```
61
+
62
+Then select **sigit** as your agent profile in the Zed assistant panel.
63
+
64
+## Other installation methods
65
+
66
+| Method | Command |
67
+|--------|---------|
68
+| npm | `npm install -g @smbcloud/sigit` |
69
+| Homebrew | `brew install getsigit/sigit/sigit` |
70
+| Cargo | `cargo install sigit` |
71
+
72
+### From source
73
+
74
+```sh
75
+git clone https://github.com/getsigit/sigit
76
+cd sigit
77
+cargo build --release
78
+./target/release/sigit
79
+```
80
+
81
+## Platform support
82
+
83
+Pre-built native binaries ship for every major platform:
84
+
85
+| Platform | Architecture |
86
+|---------------|--------------|
87
+| macOS | arm64, x64 |
88
+| Linux (glibc) | arm64, x64 |
89
+| Windows | arm64, x64 |
90
+
91
+## Source & issues
92
+
93
+This package ships a pre-built native binary. Source lives at
94
+[github.com/getsigit/sigit](https://github.com/getsigit/sigit) —
95
+file bugs and feature requests there.
96
+
97
+## License
98
+
99
+Licensed under **Apache 2.0**.
100
+
101
+- [Apache License 2.0](https://github.com/getsigit/sigit/blob/main/LICENSE)
102
+
103
+---
104
+
105
+<p align="center">
106
+ <sub>Built by <a href="https://smbcloud.xyz">smbCloud</a> (Splitfire AB) · © 2026</sub>
107
+</p>
\ No newline at end of file
pypi/pyproject.toml
new
+38
@@ -0,0 +1,38 @@
1
+[build-system]
2
+requires = ["maturin>=1.7,<2.0"]
3
+build-backend = "maturin"
4
+
5
+[project]
6
+name = "sigit-code"
7
+description = "AI coding agent powered by local LLM via Onde Inference."
8
+readme = "README.md"
9
+requires-python = ">=3.8"
10
+dynamic = ["version"]
11
+license = { text = "Apache-2.0" }
12
+authors = [{ name = "Seto Elkahfi", email = "hej@setoelkahfi.se" }]
13
+keywords = ["sigit", "cli", "ai", "coding-agent", "llm", "on-device"]
14
+classifiers = [
15
+ "Development Status :: 4 - Beta",
16
+ "Environment :: Console",
17
+ "Intended Audience :: Developers",
18
+ "License :: OSI Approved :: Apache Software License",
19
+ "Operating System :: MacOS",
20
+ "Operating System :: Microsoft :: Windows",
21
+ "Operating System :: POSIX :: Linux",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Rust",
24
+ "Topic :: Scientific/Engineering :: Artificial Intelligence",
25
+ "Topic :: Software Development",
26
+ "Topic :: Utilities",
27
+]
28
+
29
+[project.urls]
30
+Homepage = "https://smbcloud.xyz"
31
+Documentation = "https://github.com/getsigit/sigit"
32
+Repository = "https://github.com/getsigit/sigit"
33
+Issues = "https://github.com/getsigit/sigit/issues"
34
+
35
+[tool.maturin]
36
+manifest-path = "../Cargo.toml"
37
+bindings = "bin"
38
+strip = true
rust-toolchain.toml
new
+2
@@ -0,0 +1,2 @@
1
+[toolchain]
2
+channel = "stable"