Skip to content

Commit ec7dd4f

Browse files
committed
Automate Homebrew formula bump on tag; document the app/MCP consumer contract
1 parent 6186137 commit ec7dd4f

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

.github/workflows/release.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
name: Release
2+
3+
# Tag a release and everything else is automatic: this publishes the GitHub release and
4+
# bumps the Homebrew formula (url + version + sha256) so `brew install/upgrade devkit`
5+
# always tracks the latest tag. The only manual step is `git tag vX.Y.Z && git push --tags`.
6+
on:
7+
push:
8+
tags:
9+
- 'v*'
10+
11+
jobs:
12+
release:
13+
runs-on: ubuntu-latest
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- name: Compute version and source-tarball sha256
18+
id: meta
19+
env:
20+
TAG: ${{ github.ref_name }}
21+
REPO: ${{ github.repository }}
22+
run: |
23+
VERSION="${TAG#v}"
24+
URL="https://github.com/$REPO/archive/refs/tags/$TAG.tar.gz"
25+
# The tag archive can lag a few seconds behind the tag push; retry briefly.
26+
SHA=""
27+
for _ in 1 2 3 4 5 6; do
28+
SHA=$(curl -fsSL "$URL" | shasum -a 256 | awk '{print $1}') || SHA=""
29+
[ -n "$SHA" ] && break
30+
sleep 5
31+
done
32+
[ -n "$SHA" ] || { echo "::error::could not compute sha256 for $URL"; exit 1; }
33+
{
34+
echo "version=$VERSION"
35+
echo "url=$URL"
36+
echo "sha256=$SHA"
37+
} >> "$GITHUB_OUTPUT"
38+
39+
- name: Publish GitHub release
40+
env:
41+
GH_TOKEN: ${{ github.token }}
42+
TAG: ${{ github.ref_name }}
43+
REPO: ${{ github.repository }}
44+
VERSION: ${{ steps.meta.outputs.version }}
45+
run: |
46+
gh release view "$TAG" --repo "$REPO" >/dev/null 2>&1 \
47+
|| gh release create "$TAG" --repo "$REPO" --title "devkit $VERSION" --generate-notes
48+
49+
- name: Bump Homebrew formula
50+
env:
51+
GH_TOKEN: ${{ secrets.HOMEBREW_TAP_GITHUB_TOKEN }}
52+
VERSION: ${{ steps.meta.outputs.version }}
53+
URL: ${{ steps.meta.outputs.url }}
54+
SHA256: ${{ steps.meta.outputs.sha256 }}
55+
run: |
56+
git clone "https://x-access-token:${GH_TOKEN}@github.com/djadmin/homebrew-tap.git"
57+
cd homebrew-tap
58+
# Update only the CLI formula (devkit.rb); the app cask lives in Casks/ and is
59+
# released from the devkit-app repo.
60+
sed -i "s|^ url \".*\"| url \"$URL\"|" devkit.rb
61+
sed -i "s|^ sha256 \".*\"| sha256 \"$SHA256\"|" devkit.rb
62+
sed -i "s|^ version \".*\"| version \"$VERSION\"|" devkit.rb
63+
git config user.email "ci@devkit"
64+
git config user.name "devkit-ci"
65+
git add devkit.rb
66+
git diff --staged --quiet || git commit -m "devkit $VERSION"
67+
git push

CLAUDE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,27 @@ asserts a stray `~/devkit` is ignored, not adopted).
3535
The live registry is `apps.json`, which is local-only and gitignored.
3636
The committed example registry is `apps.example.json`.
3737

38+
## Consumer contract (the Mac app + MCP build on this)
39+
40+
The CLI is the single brain; the menu bar app and the MCP server are thin clients that
41+
shell out to it and parse its output. Treat these as a stable public contract — other
42+
programs depend on them, so do not break them casually:
43+
44+
- `devkit list --json` — one JSON object per app (`name`, `port`, `hostname`, `state`,
45+
`path`, `managedBy`, and the failed-start reason / log path). This is how clients read
46+
state instead of re-deriving it (which would drift). `state` is one of
47+
`running | stopped | failed | external`.
48+
- `devkit paths``KEY=value` lines (`DEVKIT_HOME`, `APPS_JSON`, `LOGS_DIR`, ...). Clients
49+
resolve locations from here, never by hardcoding `~/.devkit`.
50+
- `devkit scan --json`, `devkit doctor --json` — machine-readable, same spirit.
51+
- **Exit codes matter**: 0 = success, non-zero = failure (clients branch on this).
52+
- **Every command must terminate** non-interactively (no `tail -f`-style hangs) — an agent
53+
or the app may invoke any of them.
54+
55+
Versioning: additive changes (new fields/commands) are a minor bump; renaming/removing a
56+
field or changing `state` values is a breaking change — bump major and update the app/MCP
57+
in lockstep. Keeping this contract stable is what lets the three surfaces stay in sync.
58+
3859
## Generated files
3960

4061
Do not edit these by hand:

0 commit comments

Comments
 (0)