Add the TZGyn dev skill

This commit is contained in:
2026-09-28 12:23:22 +08:00
commit 30290801fe
3 changed files with 226 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
.DS_Store
+26
View File
@@ -0,0 +1,26 @@
# TZGyn-skill
My personal Crush skill: conventions for starting a project on Gitea, publishing
to the TZGyn Homebrew tap (casks for GUI apps, formulae for CLIs), and signing /
notarizing / releasing macOS apps.
See [SKILL.md](./SKILL.md).
## Install (global Crush skill)
```bash
git clone https://gitea.tzgyn.dev/TZGyn/TZGyn-skill.git ~/Git/TZGyn-skill
mkdir -p ~/.agents/skills
ln -s ~/Git/TZGyn-skill ~/.agents/skills/TZGyn-skill
```
The symlink means edits to this repo are the live skill. Start a new Crush
session (or run `crush_info`) to see it loaded.
## Updating
```bash
cd ~/Git/TZGyn-skill
# edit SKILL.md
git commit -am "<what changed>" && git push
```
+199
View File
@@ -0,0 +1,199 @@
---
name: TZGyn-skill
description: Use for any TZGyn development workflow — starting a new project on Gitea, publishing to the TZGyn Homebrew tap (casks for GUI apps, formulae for CLIs), signing and notarizing a desktop/mobile build, cutting a release, or extending/updating this skill itself.
---
# TZGyn dev skill
Personal conventions for TZGyn projects. Source of truth is the Git repo
`https://gitea.tzgyn.dev/TZGyn/TZGyn-skill`; it is installed as a global Crush
skill at `~/.agents/skills/TZGyn-skill` (a symlink to the checkout, so editing
the repo updates the live skill).
The reference implementations to copy from are `~/Git/kapture` and
`~/Git/konference` (macOS menu-bar apps).
## Ground rules
- **Host**: Gitea at `https://gitea.tzgyn.dev`, owner `TZGyn`, `tea` login name
`gitea.tzgyn.dev`. SSH: `git@gitea.tzgyn.dev:TZGyn/<repo>.git`.
- **Always print the upgrade script** (the `brew` commands below) in the final
answer after any release or version bump. The user wants it every time.
- Never commit build artifacts. `.gitignore` covers `.build/`, `*.app/`,
`dist/`, `.swiftpm/`, `xcuserdata/`, `DerivedData/`, `.DS_Store`.
- Never commit secrets (`.p8`, API keys) or push to a remote unless asked.
- Commit messages: concise, why-focused, first line < 72 chars; add a body only
when it helps a future reader.
- Prefer SwiftPM (Swift/SwiftUI) for macOS apps; no external dependencies.
## 1. New project on Gitea
```bash
# 1. Create the repo (as the authenticated user).
tea repos create --name <repo> --desc "<one-line description>" --login gitea.tzgyn.dev
# Do NOT pass --owner TZGyn: that hits /orgs/TZGyn/repos and 404s for a user.
# 2. Initialise and push.
cd ~/Git/<repo>
git init -b main
git add -A && git commit -m "<why>"
git remote add origin https://gitea.tzgyn.dev/TZGyn/<repo>.git
git push -u origin main
```
Scaffold every repo with `README.md`, `AGENTS.md` (architecture + commands +
gotchas), and `.gitignore`. See `~/Git/simpletopbar` for the minimal shape:
`Package.swift`, `Sources/<Name>/*.swift`, `build-app.sh`, `release.sh`,
`scripts/`.
## 2. Homebrew tap
- The tap clone lives at **`~/.cache/homebrew-tap`**
(origin `https://gitea.tzgyn.dev/TZGyn/homebrew-tap.git`).
- Layout: **GUI apps → `Casks/<name>.rb`**; **CLI tools → `Formula/<name>.rb`**.
- After pushing, sync Homebrew's own clone:
```bash
git -C ~/.cache/homebrew-tap add -A
git -C ~/.cache/homebrew-tap commit -m "Add <name> cask"
git -C ~/.cache/homebrew-tap push
git -C /opt/homebrew/Library/Taps/tzgyn/homebrew-tap pull --ff-only
brew audit --cask tzgyn/tap/<name> # or: brew audit --formula tzgyn/tap/<name>
```
- Users tap once (non-GitHub taps need the full URL):
```bash
brew tap TZGyn/tap https://gitea.tzgyn.dev/TZGyn/homebrew-tap.git
brew trust TZGyn/tap
```
### Cask (GUI app)
```ruby
cask "<name>" do
version "X.Y.Z"
sha256 "<sha256 of the release zip>"
url "https://gitea.tzgyn.dev/TZGyn/<repo>/releases/download/v#{version}/<Asset>.zip"
name "<Display Name>"
desc "<one line>"
homepage "https://gitea.tzgyn.dev/TZGyn/<repo>"
app "<Name>.app"
end
```
### Formula (CLI)
```ruby
class <Name> < Formula
desc "<one line>"
homepage "https://gitea.tzgyn.dev/TZGyn/<repo>"
url "https://gitea.tzgyn.dev/TZGyn/<repo>/releases/download/v0.1.0/<asset>-0.1.0-darwin-arm64.tar.gz"
sha256 "<sha256 of the tarball>"
version "0.1.0"
def install
bin.install "<binary>"
end
end
```
## 3. Releasing a macOS GUI app
Two scripts per repo: `build-app.sh <version>` and `release.sh <version>`.
1. **Build + sign** (`build-app.sh`): `swift build -c release` → handwritten
`Info.plist` (NOT generated from `Package.swift`) → `make-icon.sh` → sign
with the Developer ID identity resolved from the login keychain
(`security find-identity -v -p codesigning | awk '/Developer ID Application:/{print $2;exit}'`),
falling back to ad-hoc (`-`). GUI apps set `LSUIElement = true` and
`CFBundleIdentifier = dev.tzgyn.<name>`.
2. **Notarize + staple + zip** (`release.sh`): build → `ditto -c -k --keepParent
<App>.app dist/<App>.zip` → submit to Apple → staple → re-zip → print sha256.
See [Notarization](#4-notarization) for the credentials.
3. **Publish the release** and attach the zip:
```bash
tea releases create --tag v<version> --title "<App> <version>" \
--note "<what changed>" --asset dist/<App>.zip \
--repo TZGyn/<repo> --login gitea.tzgyn.dev
```
4. **Bump the cask** (`version` + `sha256`), push the tap, pull Homebrew's
clone, `brew audit`. Verify by downloading the asset back and comparing the
sha256, and `spctl -a -vv <App>.app` → `accepted` /
`source=Notarized Developer ID`.
5. **Print the upgrade script**:
```bash
brew update
brew upgrade --cask <name>
```
## 4. Notarization
Signing identity: `Developer ID Application: Teh Zi Gyn (RX6767S6BW)`.
App Store Connect API key (shared with Kapture):
| Value | Where |
| --------- | ------------------------------------------------------------ |
| Key file | `~/.config/kapture/AuthKey_K5KXMMSB28.p8` |
| Key ID | `K5KXMMSB28` |
| Issuer ID | `3e25e5dc-8b75-453f-a71c-c7f3feaac628` (not secret) |
| Team ID | `RX6767S6BW` |
Signing must use a hardened runtime and a secure timestamp:
```bash
codesign --force --options runtime --timestamp --sign "$IDENT" "<App>.app"
```
Submit and verify:
```bash
xcrun notarytool submit dist/<App>.zip \
--key "$HOME/.config/kapture/AuthKey_K5KXMMSB28.p8" \
--key-id K5KXMMSB28 --issuer 3e25e5dc-8b75-453f-a71c-c7f3feaac628 \
--wait --output-format json
xcrun stapler staple <App>.app && xcrun stapler validate <App>.app
spctl -a -vv <App>.app # want: accepted, source=Notarized Developer ID
```
Wire `release.sh` so it notarizes when `NOTARY_*` env vars are set and otherwise
skips gracefully (build + zip + sha only). An unnotarized app is still signed but
Gatekeeper warns on other machines; the user can bypass with
`xattr -dr com.apple.quarantine <App>.app` or install with
`brew install --cask --no-quarantine <name>`.
## 5. Mobile
For mobile (iOS/Android), notarization does not apply; the equivalent is store
signing (App Store Connect / Play Console) or EAS. Ask for the specific stack
before assuming; this skill currently only codifies the macOS path.
## 6. Extending this skill (self-improvement)
This skill is meant to grow. When the user asks for a new behaviour, preference,
or convention:
1. Edit the relevant section of `SKILL.md` (add a new section if it is a new
topic). Keep it concrete: exact commands, paths, and templates.
2. Keep it truthful — only document what has actually worked; delete steps that
became stale (e.g. a changed path or flag).
3. Commit and push:
```bash
cd ~/Git/TZGyn-skill
git add -A && git commit -m "<what behaviour was added>"
git push
```
4. The installed copy is a symlink, so it updates immediately; a new Crush
session picks it up. Confirm with `crush_info` (the skill should appear under
`[skills]`).
Prefer updating this skill over repeating ad-hoc instructions in a project: if a
convention applies to more than one repo, it belongs here.