Skip to content

feat!: collapse seven skills into one router skill - #18

Merged
posidoni merged 9 commits into
mainfrom
feat/single-router-skill
Jul 19, 2026
Merged

feat!: collapse seven skills into one router skill#18
posidoni merged 9 commits into
mainfrom
feat/single-router-skill

Conversation

@posidoni

Copy link
Copy Markdown
Owner

Why

The kit exported seven separate skills (bash, zsh, posix-sh, nushell, shell-standards, shebang, streams). An agent had to already know which one it needed — but the decision an agent actually faces is "should this be shell at all?", and that question was answered by none of them.

Worse, the seven descriptions competed with each other on load, so the most useful one frequently lost.

What changed

One router skill (skills/shell/). It answers "should this be shell?" first — usually the answer is jq, yq, sd, nu, Python or bun — then routes to the per-shell reference for whatever survives that question. The seven SKILL.md files collapse into one; their content moves to reference/, loaded on demand.

Trigger-first description. The description now fires on the act ("you are about to type awk, sed, cut, or a second pipe") rather than on a request to write shell. Skills lose to recency in a long context; a situational trigger fires when it matters.

New reference/cli-cheatsheets.md. Cached essentials for fd, rg, sd, nu, jq, yq, sttr — verified against installed versions, which are recorded so a reader knows when to re-check. It deliberately does not replace --help; it records the defaults that silently do the wrong thing:

  • fd/rg honour .gitignore as well as hiding dotfiles. -H fixes only half — you need -I. This costs an hour every time, and the file you are hunting (.db, .env) is usually gitignored, which is precisely why you are hunting it.
  • There is no sed -i invocation portable across BSD and GNU. sed -i 's/a/b/' f works on GNU and errors on macOS; sed -i '' 's/a/b/' f works on macOS and creates a file named '' on GNU. Hence sd.
  • $nu.home-path does not exist — check $nu | columns before using any $nu.* field.

New reference/pipelines.md. Replacement table, BSD-vs-GNU traps, worked rewrites. Hard stop: three or more pipeline stages, or any awk beyond {print $1}, means write a script file.

nu -n -c guidance. Without -n/--no-config-file, nu -c loads the user's config.nu/env.nu and inherits their aliases, $env, and any parse-time source — so the command stops being deterministic. Same argument as pinning an interpreter.

AI-integration surfaces. REGISTRY.md, llms.txt, JSON schemas for Codex plugin / OpenAI skill metadata / Serena project, plus tools/check-ai-integrations.sh and tools/check-yaml-schemas.sh wired into the Taskfile so the surfaces are checked, not just claimed.

Breaking

feat! — the six removed skill names no longer resolve. Anything referencing shell-standards, bash, zsh, posix-sh, nushell, shebang, or streams as a skill must now use shell. The content is not gone; it moved to reference/ behind the router.

Verification

task ci passes on this branch: ShellCheck across all non-bad scripts, the good-vs-bad example contract (every .bad.sh must produce its documented SC code), nu --ide-check on every .nu, the Nushell startup-order demo (all 3 cases), the bats suite, formatting, and the YAML-schema check.

🤖 Generated with Claude Code

posidoni added 6 commits July 18, 2026 14:17
Seven sibling skills competed for the same request and none carried a
trigger-first description, so the kit went unused while agents wrote unsafe
shell. One 'shell' skill now routes into reference/ on demand.

Adds reference/pipelines.md covering the awk/sed replacement table, the
non-portable sed -i, and interpreter selection (macOS /bin/bash is 3.2).

BREAKING: shell-skill:bash and the other six are now shell-skill:shell.
…dance

Description now fires on the act (about to type awk, parsing du/ps output,
nesting $(...)) rather than on an explicit request for shell help.

Adds nu invocation forms to reference/nushell.md: agent and CI one-liners
need -n/--no-config-file, or they inherit the user's config.nu and env.nu
and stop being deterministic.
Adds the escalation ladder (--help -> man -> context7 -> web) to the skill,
and reference/cli-cheatsheets.md with defaults that silently do the wrong
thing -- notably fd/rg honouring .gitignore, where -H fixes only half the
problem and -I is the other half. Verified against installed versions.
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request consolidates seven separate shell skills into a single, unified shell skill and introduces new integration gates and configurations for Codex, ChatGPT, Claude Code, and Serena. Key additions include JSON Schema modelines for YAML-like files, automated validation scripts for schemas and AI integrations, and updated documentation reflecting the new 'Shell Skill Kit' branding. Feedback on the changes suggests optimizing tools/check-yaml-schemas.sh by using the Bash builtin read -r instead of spawning sed subprocesses in a loop, and leveraging Nushell in tools/check-ai-integrations.sh to parse YAML frontmatter robustly instead of using a fragile awk script.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +4 to +15
status=0

while IFS= read -r file; do
if [[ ! -f "$file" ]]; then
continue
fi

first_line=$(sed -n '1p' "$file")
if [[ ! $first_line =~ ^#\ yaml-language-server:\ \$schema= ]]; then
printf 'missing first-line YAML schema comment: %s\n' "$file" >&2
status=1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using sed in a loop to read the first line of each file creates a new subprocess for every file, which can significantly degrade performance when checking many files. Additionally, the unquoted regex pattern ^#\ yaml-language-server:\ \$schema= contains an unquoted $ inside double brackets, which can lead to parsing and portability issues across different shell versions and platforms.

We can optimize this by using the Bash builtin read -r to read the first line without forking a subprocess, and by storing the regex pattern in a variable to ensure robust and portable matching.

Suggested change
status=0
while IFS= read -r file; do
if [[ ! -f "$file" ]]; then
continue
fi
first_line=$(sed -n '1p' "$file")
if [[ ! $first_line =~ ^#\ yaml-language-server:\ \$schema= ]]; then
printf 'missing first-line YAML schema comment: %s\n' "$file" >&2
status=1
fi
status=0
schema_pattern='^# yaml-language-server: \$schema='
while IFS= read -r file; do
if [[ ! -f "$file" ]]; then
continue
fi
first_line=""
read -r first_line < "$file" || :
if [[ ! $first_line =~ $schema_pattern ]]; then
printf 'missing first-line YAML schema comment: %s\n' "$file" >&2
status=1
fi

Comment thread tools/check-ai-integrations.sh Outdated
Comment on lines +106 to +114
skill_name=$(awk '
$0 == "---" { fence++; next }
fence == 1 && $1 == "name:" {
sub(/^name:[[:space:]]*/, "", $0)
gsub(/^["'\'']|["'\'']$/, "", $0)
print $0
exit
}
' "$skill_md")

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Since Nushell (nu) is already a required dependency of this repository and is used extensively in this script, we can leverage it to parse the YAML frontmatter of SKILL.md files robustly. This avoids relying on a complex and potentially fragile hand-rolled awk parser for YAML frontmatter, aligning perfectly with the repository's guideline: 'Structured data deserves a structured tool'.

Suggested change
skill_name=$(awk '
$0 == "---" { fence++; next }
fence == 1 && $1 == "name:" {
sub(/^name:[[:space:]]*/, "", $0)
gsub(/^["'\'']|["'\'']$/, "", $0)
print $0
exit
}
' "$skill_md")
skill_name=\$(nu -c "open '$skill_md' | split row '---' | get 1 | from yaml | get name")

posidoni and others added 3 commits July 19, 2026 18:06
Serena's memory store was empty -- 0 files in ~/.serena/memories -- while the
install carried 182 MB of bundled language servers. The six .serena/memories/
files tracked in this repo were Serena's own auto-generated onboarding output
(conventions, tech_stack, suggested_commands, task_completion, core,
memory_maintenance), restating README.md and the Taskfile while drifting from
them. Editor/agent integration state does not belong in a public repo.

Removes .serena/, schemas/serena-project.schema.json, the Serena block in
tools/check-ai-integrations.sh, and the references in REGISTRY.md, llms.txt,
README.md, AGENTS.md, CONTRIBUTING.md, CHATGPT.md, Taskfile.yml and
lefthook.yml. .gitignore now ignores .serena/ wholesale instead of
whitelisting parts of it.

task ci and task ai-integrations both pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review suggestions (gemini-code-assist, PR #18):

1. check-yaml-schemas.sh forked `sed -n 1p` once per file inside the loop.
   Replaced with the `read` builtin. Also moved the regex into a variable
   expanded unquoted in [[ =~ ]] -- the inline backslash-escaped form worked
   but silently degrades on edit.

2. check-ai-integrations.sh hand-rolled a YAML frontmatter parser in awk,
   re-implementing fence tracking, key matching and quote stripping. This kit
   teaches 'no awk beyond {print $1}' and 'structured data deserves a
   structured tool', so it now parses with nu.

   The suggested replacement was `nu -c "open '$f' | split row ..."`, which
   fails: `open` on a .md path does not return a string, so `split row`
   errors with only_supports_this_input_type. Needs --raw. It also omitted
   -n/--no-config-file, which this kit's own skill requires so the command
   does not inherit the user's config.nu.

3. Restores macOS CI, dropped when four jobs were consolidated into one.
   tools/ci-install-macos.sh survived as dead code, and its own header
   explains why the job exists: a portability signal for a repo whose premise
   is that BSD and GNU behave differently. A Linux-only gate cannot verify
   what this kit teaches.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The restored macOS job used `task ci`, which also runs the nushell gate.
Homebrew's nushell is unpinned and the macos-14 runner currently ships
0.113.1, while the Linux job and local dev pin 0.114.1. The input/output
signature in examples/nushell/03-typed-command.nu is 0.114+ syntax, so 0.113.1
parses `nothing` as a stray positional and --ide-check fails.

That is version skew, not a platform difference -- nu is a single Rust binary
and behaves identically on macOS and Linux. Linux owns the nushell gate at a
pinned version; this job owns bash, shfmt and ShellCheck, which genuinely do
differ across BSD and GNU. Same step list the original shell-macos job had.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@posidoni
posidoni merged commit 3ad95c9 into main Jul 19, 2026
2 checks passed
@posidoni
posidoni deleted the feat/single-router-skill branch July 19, 2026 14:22
posidoni added a commit that referenced this pull request Jul 19, 2026
Collapsing seven skills into one router deleted skills/{nushell,shebang,
streams,zsh}/ but left reference/{nushell,shebang,streams,zsh}.md linking to
them. All five gates stayed green through the merge because none of them
reads a link -- in a repo whose product is its documentation, that is a real
hole. The four now point at skills/shell/.

tools/check-doc-links.sh resolves every relative Markdown link against its own
file's directory and fails on any miss. External URLs are deliberately not
fetched: needs network, slow, and turns someone else's outage into a red
build. Verified both ways -- 83 links resolve, and an injected bad link fails
the run.

Wired into task ci, a standalone task doc-links, and lefthook pre-commit on
*.md. The hook self-scans the whole tree rather than only staged files,
because moving one file breaks links in files the commit never touches --
exactly how this shipped.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant