From beislid
Interactively configures Beislið project workflow in .beislid/workflow.md using git prechecks, ticket source detection, and conversational menus. Shows diffs before writes; activates on setup/configure intents.
npx claudepluginhub sandsower/beislidThis skill uses the workspace's default tool permissions.
Initialize or update Beislið's per-project config at `<repo>/.beislid/workflow.md`. Setup is the canonical config interface — direct file editing still works as an escape hatch but isn't surfaced in user-facing prose.
Starts ticket work after feature branch checkout: fetches ticket, explores codebase, routes vague/large tickets to spec/break-spec, then blueprint/implement. Driven by .beislid/workflow.md.
Initializes new projects: checks setup, inits git, detects brownfield code (TS/JS/Py/Go/Rust/Swift/Java), offers codebase mapping, gathers context for PROJECT.md/config.json.
Initializes FLOW projects by configuring workspace permissions, git excludes, installing bin stubs, setting skill autonomy levels, and committing changes. Run once after install or upgrade.
Share bugs, ideas, or general feedback.
Initialize or update Beislið's per-project config at <repo>/.beislid/workflow.md. Setup is the canonical config interface — direct file editing still works as an escape hatch but isn't surfaced in user-facing prose.
First run (no workflow.md): run a minimal-required interview (ticket source, branch pattern, default PR base, probe cache), write the file, insert a ## Agent skills block in AGENTS.md, then offer the same menu shown on re-run for adding optional sections.
Re-run (workflow.md exists): show a menu — add a section, change a configured section, remove a configured section, reset and regenerate, or cancel. Never silently overwrites; every destructive write shows a diff and asks for confirmation.
Format reference: workflow-md-format.md (symlink to the master). Probe semantics for capability discovery: probe-semantics.md (symlink to the master).
Run git rev-parse --show-toplevel. If it errors or returns non-zero, hard-fail with prose:
🛑 Setup needs a git repo with at least one commit. Run `git init` and make
the first commit, then re-run /setup.
Also check git rev-list --max-parents=0 HEAD exits 0 (at least one commit). Same hard-fail otherwise.
Check <git-toplevel>/.beislid/workflow.md:
Run cheap-signal commands once at the top, before asking anything:
git remote get-url origin # → host + owner/repo
gh auth status 2>&1 # → is gh CLI logged in?
git log -50 --pretty=%s # → grep for ID patterns
git for-each-ref refs/heads --format='%(refname:short)' --sort=-committerdate \
| head -20 # → branch_pattern candidates
Parse git remote for host (github.com / gitlab.com / etc.) and owner/repo. Parse gh auth status for the auth state on github hosts. Grep commit subjects for [A-Z]{2,4}-\d+ (Linear/Jira shape) and ^#?\d+ (GitHub/Azure numeric shape). Hold these results in memory for the interview prompts.
Use the inspection results to suggest a default. One suggestion at a time, single Y/n confirmation; never silent fill.
If host is github.com + gh authed + numeric IDs detected in commits:
🔍 Detected GitHub Issues with `gh` CLI (numeric IDs in recent commits).
Use `type: cli, command: 'gh issue view {id} --json title,body,labels'`?
[Y/n/different]
On Y: capture id_pattern: '^#?\d+$' and link_template: 'https://github.com/<owner>/<repo>/issues/{id}' (deterministic from git remote).
If Linear-shaped IDs detected ([A-Z]+-\d+):
Try MCP discovery via probe-semantics.md (search for tools matching *linear* or *issue*). On match:
🔍 Linear-shaped IDs in recent commits + Linear MCP tool detected
(`<tool-name>`). Use this for ticket fetching? [Y/n/different]
On Y: capture type: mcp, tool: <tool-name>, id_pattern: '^[A-Z]+-\d+$'. Ask once for the workspace name to populate link_template: 'https://linear.app/<workspace>/issue/{id}'.
If MCP discovery returns no Linear-shaped tools: do NOT ask the user to type an MCP tool name. Pivot:
💭 Linear-shaped IDs detected but no Linear MCP tool is available in this
host. Pick an alternative:
(a) cli — give me the command for fetching tickets
(b) paste — I'll ask for the title at every ship
If no detectable signal: ask (mcp / cli / file / paste) directly. For mcp: list available MCP tools via probe-semantics.md and ask to pick one. For cli: ask for the command (must contain {id} placeholder). For file: ask for the file glob. For paste: no further input.
In every branch, capture id_pattern (auto-derived from the dominant grep pattern) and link_template for known hosts (deterministic). Never ask the user to type an MCP tool name.
Test these 8 candidate regexes against the last 20 branches. Sort by coverage (number of branches that match).
1. ^[a-z]+/([a-z]+-\d+) — case-mismatched (normalize via id_pattern)
2. ^[a-z]+/([A-Z]+-\d+) — Jira with type prefix
3. ^([A-Z]+-\d+) — Jira/Linear direct uppercase
4. ^([a-z]+-\d+) — direct lowercase
5. ^(\d+)- — github/azure numbered with description
6. ^[a-z]+/(\d+) — feature/123 (Azure DevOps, GitHub)
7. ^[a-z]+/[a-z]+/(\d+) — Azure DevOps users/<name>/12345
8. ^[a-z]+-(\d+) — gh-123 style
Suggest the highest-coverage candidate with stats:
🔍 Branch pattern `^[a-z]+/([a-z]+-\d+)` matches 18 of 20 recent branches.
Use it? [Y/n/skip]
If best coverage <60%: don't suggest a pattern. Ask:
💭 No regex covers most recent branches. Skip branch_pattern? Ship-it will
ask for the ticket ID at every run. [Y/n]
On n: ask for the regex directly. On Y (skip): capture nothing for branch_pattern.
Probe order:
gh repo view --json defaultBranchRef -q .defaultBranchRef.name.git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@'.main.If the result is main: silent default — don't ask. If the result is anything else, confirm:
🔍 Default branch detected: `<branch>`. Use as pr_base? [Y/n]
On n: ask the user for the branch name.
Compose in memory:
<!-- beislid-workflow: v1 --> (line 1).basename $(git rev-parse --show-toplevel).## Issue tracker section with the captured ticket_source and (if present) branch_pattern blocks.## PR target section with pr_base.default (only if non-main).## Probe cache section with ttl_hours: 24.No commented-out templates. Only sections the user filled in.
Print the composed workflow.md to the user. Wait for explicit approval:
📋 Preview of `.beislid/workflow.md`:
<composed contents>
Write this to `<git-toplevel>/.beislid/workflow.md`? [Y/n]
On n: cancel without writing. On Y: continue to step 9.
Run mkdir -p <git-toplevel>/.beislid/ then write the file. Print:
📝 Wrote .beislid/workflow.md
Then run the AGENTS.md block insertion (section 12 below).
After writing the minimum, offer the menu mode (section 11 — same UI as re-run) for adding optional sections.
Print one nudge to run /doctor:
💭 Next: run /doctor to verify the config and warm the probe cache.
When .beislid/workflow.md already exists, parse it (using the grammar in workflow-md-format.md). If parsing fails, jump to section 13: parse-error recovery. Otherwise present:
📋 Found .beislid/workflow.md. What would you like to do?
(1) Add a section
(2) Change a configured section
(3) Remove a configured section
(4) Reset and regenerate from scratch
(5) I'm done
On (1) Add a section: present a sub-menu of optional sections that aren't yet configured. Each item shows a one-line "when this fires" hint (plain English, not phase-numbered):
Walk the chosen section's sub-interview (asking one Y/N or value at a time). Compose the section block in memory. Insert at the canonical position in the file (canonical order is the order in workflow-md-format.md § Section grammar). Show diff (git diff --no-index <old> <new> formatted prose). Ask Write? [Y/n]. On Y: write atomically (whole-file rewrite via Read → mutate → Write).
On (2) Change a configured section: show currently filled sections only. Walk that section's sub-interview pre-filled with current values; user accepts or overrides each value. Show diff; confirm; write.
On (3) Remove a configured section: show currently filled sections only. On selection, check section-dependency rules and prompt for auto-clean:
scopes while split_policy is set → "Removing scopes will also remove split_policy (it has no meaning without scopes). Proceed? [Y/n]"domain_expert.agent while knowledge_store.path is set → "Also remove knowledge_store.path? [Y/n]" (default Y; if n, leaves the half-pair)knowledge_store.path while domain_expert.agent is set → mirrorpr_review_source while pr_review_update is set → warn that update can only be used after pasted PR feedback; ask whether to remove update too (default Y)pr_review_update while pr_review_source is set → allowed; heard-chef will print PR reply/re-request instructions manuallyShow diff; confirm; write.
On (4) Reset and regenerate from scratch:
<git-toplevel>/.beislid/workflow.md.bak. Print: 📝 Saved current config to .beislid/workflow.md.bak.Write? [Y/n].Y: write atomically.On (5) I'm done: exit cleanly with no writes.
Configure the canonical ticket_update block. This is shared by kickoff and heard-chef: kickoff uses only the comment channel to post the approved implementation plan; heard-chef uses the comment channel for QA/ticket replies and the issue channel for out-of-scope child tickets.
Ask for one mode:
Configure ticket updates? (mcp / cli / skip)
For mcp, ask for comment_tool first and issue_tool second. The issue tool is optional; if omitted, heard-chef prints child-ticket drafts manually.
type: mcp
comment_tool: mcp__linear__save_comment
issue_tool: mcp__linear__save_issue
For cli, ask for comment_command first and issue_command second. Commands must use temp-file placeholders so user-authored text is never interpolated into the shell: {id} and {body_file} for comments; {title_file} and {body_file} for issues. If the user proposes {body} or {title}, explain the injection/quoting risk and ask for a file-based command instead.
type: cli
comment_command: '... {id} ... {body_file} ...'
issue_command: '... {title_file} ... {body_file} ...'
If git remote get-url origin parses as GitHub and gh auth status passes, suggest GitHub CLI defaults:
Use GitHub CLI to read PR reviews and post clear-fix replies? (Y / manual replies / n)
On Y, write both blocks:
type: cli
summary_command: 'gh pr view --json url,number,reviewDecision,reviews,comments'
threads_command: 'gh api repos/{owner}/{repo}/pulls/{number}/comments'
type: cli
reply_command: 'gh api repos/{owner}/{repo}/pulls/{number}/comments --method POST --input {json_file}'
rerequest_command: 'gh api repos/{owner}/{repo}/pulls/{number}/requested_reviewers --method POST --input {json_file}'
On manual replies, write the same pr_review_source and this update block:
type: manual
On n, or when the repo is not GitHub/authed, ask for source mode: cli / paste / skip.
For source cli, ask for summary_command first. It may use {owner}, {repo}, {number}, and {url} placeholders; if it uses any of those, setup should remind the user that heard-chef will derive or ask for the values at runtime. Then ask for optional threads_command for inline review comments. Write:
type: cli
summary_command: '<user command>'
# Include threads_command only when the user supplies one.
threads_command: '<user command>'
For source paste, write an explicit manual source:
type: paste
If a source is configured, ask for update mode: cli / manual / skip.
For update cli, ask for reply_command first and require a {json_file} placeholder. The command may also use {owner}, {repo}, and {number}. Then ask for optional rerequest_command; if supplied, it must also use {json_file}. Write:
type: cli
reply_command: '<user command with {json_file}>'
# Include rerequest_command only when the user supplies one.
rerequest_command: '<user command with {json_file}>'
For update manual, write type: manual; skip leaves update absent and heard-chef prints manual instructions.
Configure pr_host.* only when the derived remote is wrong. Ask for owner and repo; ask for remote only if it is not origin.
my-org
my-repo
upstream
pr_host is pure address/config data. Setup does not probe it.
The block content is fixed:
## Agent skills
This repo uses [Beislið](https://github.com/sandsower/beislid) for orchestrator skills.
- Project config: `.beislid/workflow.md`
- Audit setup: `/doctor`
- Configure: `/setup`
Insertion logic:
<git-toplevel>/AGENTS.md exists:
## Agent skills heading. If found, replace the content between that heading and the next ## (or EOF) — keep the heading position where it is.AGENTS.md does not exist:
CLAUDE.md exists, do NOT modify it.Print:
📝 <added|updated> ## Agent skills section in <AGENTS.md path>
If .beislid/workflow.md exists but doesn't parse cleanly per workflow-md-format.md grammar, run the same line-numbered diagnosis doctor uses:
grep -n '^```beislid:' <repo>/.beislid/workflow.md
Compute the line number of the failing block, surface it in prose:
🛑 Workflow.md has a parse error.
⚠️ The `beislid:<key>` block at line <N> doesn't parse: <yaml error>.
✓ The other configured sections (<list>) parsed cleanly.
What now?
(a) Reset and regenerate from scratch — saves current file to
`.beislid/workflow.md.bak` first.
(b) Cancel — exit setup, fix workflow.md by hand or run /doctor for more
detail.
On (a): run section 11 option (4) (Reset). On (b): exit cleanly.
Don't offer Add / Change / Remove on a partially parseable file — they're unsafe without a clean parse of every section.
probe-semantics.md MCP discovery; if discovery returns nothing, pivot to cli/paste.[Y/n].[Y/n] confirmation.