General-purpose coding policy for Baruch's AI agents
73
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
When the agent's interactive Step-2 (PR create) and Step-7 (merge + cleanup) instructions get encoded into a reusable script that other devs run unattended (release.sh, merge-and-cleanup.sh, etc.), the script has to carry the SAME gates the interactive agent does — otherwise the script bypasses the conventions this skill exists to hold. Pulled out of SKILL.md to keep the main workflow scannable.
The script MUST enforce all of:
<type>(<scope>): <imperative summary>. Taking the title as a raw argument and passing it straight to gh pr create defeats the convention; either build the title from <type>, <scope>, <summary> inputs, or regex-validate the supplied title before push.The script MUST enforce all of:
skills/release/watch-pr-reviews.sh <owner> <repo> <pr-number> (script-owned interval/budget; emits .watch.result — ready on exit 0, changes_requested / ci_failure / dirty on exit 0, pending_at_budget on exit 1). Never hand-roll the poll loop or wrap the watch in an invented timeout. Then re-check the same conditions the interactive agent checks at merge time: CI status is success (or none), every bot review is APPROVED or non-blocking COMMENTED, no review thread is unresolved. Fail loudly if any gate is red instead of proceeding.rules/script-delegation.md). Any non-empty reviews.*.body must surface for an agent/human read regardless of state — APPROVED included, not just COMMENTED — mirroring Step 7's Every non-empty reviews.*.body gate. A wrapper that merges on state alone reproduces the unread-body hole rules/reviewer-feedback-reading.md exists to close.git branch -d <branch> (refuses to drop unmerged work), never git branch -D. The whole point of the cleanup is "ship and tidy"; clobbering an unmerged branch with -D defeats the safety the merge gate just established.rules/agent-worktree-isolation.md), it must detect that case and run the worktree variant of cleanup: cd to the base checkout, fast-forward main, git worktree remove <worktree-root>, then git branch -d <branch>. Three derivations the wrapper needs:
[ "$(git rev-parse --git-dir)" != "$(git rev-parse --git-common-dir)" ]; true means you're in an additional worktreegit rev-parse --show-toplevel (required by git worktree remove, which refuses subdirectory paths with not a working tree)git worktree list --porcelain | awk '/^worktree / {print $2; exit}' (the first worktree entry is always the main checkout)
Skipping this branch makes git branch -d fail with a confusing "checked out at <path>" error and leaves the worktree directory plus .git/worktrees/ metadata stranded; the script must surface a coherent teardown, not that error.tessl plugin publish / tesslio/patch-version-publish publish path; a tag-triggered workflow creating a GitHub release) and runs each channel's steps below. A package on both channels runs both sets, neither standing in for the other. See rules/ci-safety.md Always Watch CI.gh pr merge, capture the registry's Latest Version as a baseline (tessl plugin info <workspace>/<plugin>). The baseline feeds the conjunction check below. A tag/asset-only publication skips it.main actually advanced to the merge commit before any further verification step runs.gh pr view <N> --json mergeCommit --jq '.mergeCommit.oid' (NOT git log -1 on main), then skills/release/resolve-publish-run.sh <owner> <repo> <merge-sha> <workflow-name>. For a tag-triggered publish, push the tag and pass it as the fifth argument alongside the commit it points at: skills/release/resolve-publish-run.sh <owner> <repo> <tag-sha> <workflow-name> <tag>. The resolver's contract is referenced once, at its invocation site in SKILL.md Step 7. A wrapper covering both channels holds one run id per channel and never overwrites one with the other. Never select by "latest on main" or any branch-only/limit-1 heuristic.jq -r '.database_id' and gh run watch <id> on that exact run. Never reduce this to "check it triggered".skills/release/verify-publish-landed.sh <workspace> <plugin> <pre-baseline> <run-id> exits 0 iff the resolved run's conclusion is success AND the registry's Latest Version is strictly greater than the pre-merge baseline. The script must NOT bypass the conjunction script's exit code (e.g., by parsing current > pre alone).pass via skills/release/verify-moderation-cleared.sh <workspace> <plugin> <version> (exponential backoff, fail loud at budget — the script owns the backoff constants and the cleared/blocked decision). A still-pending or blocked state at budget exhaustion exits non-zero; the wrapper must NOT report the release confirmed. Query the real moderation state from the registry — never fabricate one as a hedge for a failed publish.skills/release/verify-github-release.sh <owner> <repo> <tag> <run-id> exits 0 iff the resolved run's conclusion is success AND the release exists at that exact tag, is published, and every asset is retrievable. The wrapper must NOT bypass its exit code, and runs none of the three Tessl steps for this channel.skills/release/stamp-changelog.py runs in the publish workflow (.github/workflows/publish.yml), not from any SKILL.md step — the agent never invokes it. It stamps the publish-on-merge CHANGELOG so un-headed ### entries get a ## <version> — <date> heading matching the version being published.
Contract:
--changelog (default CHANGELOG.md), --manifest (default .tessl-plugin/plugin.json, then tile.json), --latest (skip the registry query; CI omits it and queries tessl plugin info), --date (default today, UTC)commit-stamp.sh) with the CI-skip marker, decoupled from the publish step's exit (#284)## headingtessl plugin info failure (auth/network is surfaced, not masked)compute_version / stamp_changelog — do not restate it hereThe workflow step must run BEFORE the publish step (smart-publish) so the stamped heading and the assigned version stay in lockstep.
The publish workflow above is a thin caller of the canonical reusable pipeline (.github/workflows/publish-plugin.yml). Wiring a new plugin repo onto that pipeline — or migrating one off a bespoke tesslio/patch-version-publish workflow — is a documented maintainer step, not part of the release flow. The caller template, the input guide, the Dependabot pin renewal, and the migration procedure live in the reference doc (repo-internal; docs/ is .tesslignored, so read it from the repo, not an install):
docs/fleet-publish-setup.mdA scripted run is unattended. Anything the interactive agent enforces by reading SKILL.md only protects the sessions where the SKILL.md is in the agent's context. A script that doesn't carry the same gates internally hands every consumer a sharper version of the bypass-by-automation problem.
.tessl-plugin
hooks
rules
skills
adopt-fork-pr
herdr-standup
herdr-teamlead
references
teamlead
templates
tests
migrate-to-plugin
onboard-repo
release
tests