generic harness: the router description's `: ` makes SKILL.md invalid YAML, so strict loaders (Pi) drop the skill
Maintainers usually reply within 1 day
Assessment
- Difficulty
- 1/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 24/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Stale
- Tech stack
- typescript, yaml
- Domain
- developer-experience, tooling
Research direction
Read lib/harness-register.ts and scripts/gen-skill-docs.ts to compare how their frontmatter writers encode descriptions, then inspect the linked PR #4165 for work already underway. The issue identifies routerSkill() and flatFrontmatter() as the affected entry points; done means both emitted descriptions parse as YAML while preserving their original text.
Written by the indexing model from the issue text.
Description
What happened
gstack-harness register generic (the "any other harness" target, docs/hosts.md) writes a SKILL.md whose frontmatter is not valid YAML: the router description contains an interior ": " (... Load first for any coding task: lists every gstack skill ...) and is emitted as a plain scalar, so a strict YAML loader reads it as a nested mapping and rejects the file.
A harness that parses frontmatter with a real YAML parser then drops the skill silently, so register reports success and the skill never appears:
gstack-harness: any other harness: 60 gstack skills reachable through one router skill at <dir> (installed, 1 files written)
…and in Pi, ~/.agents/skills/gstack/SKILL.md is never listed, with no error the user can act on (Pi documents malformed SKILL.md files as "not loaded").
This is the same class of bug as #1778 (generated SKILL.md descriptions with colons are invalid YAML), which was fixed in scripts/gen-skill-docs.ts by quoting with toYamlInlineScalar. That helper stayed local to the generator, and the two frontmatter writers in lib/harness-register.ts never got it:
routerSkill()→'description: ' + ROUTER_DESCRIPTION(router mode, the failing one)flatFrontmatter()→'description: ' + desc(--skills allfor Claude-render targets: any skill description with a colon breaks the same way)
Steps to reproduce
git clone https://github.com/garrytan/gstack && cd gstack
bun install
./bin/gstack-harness register generic --skills-dir /tmp/repro-skills
head -3 /tmp/repro-skills/gstack/SKILL.md
Then parse the frontmatter with a strict YAML loader (any: yaml, js-yaml, PyYAML, or the loader the target harness uses):
node -e 'const fs=require("fs"),{parse}=require("yaml");
const m=/^---\r?\n([\s\S]*?)\r?\n---/m.exec(fs.readFileSync(process.argv[1],"utf8"));
try{const o=parse(m[1]);console.log("OK name="+o.name)}catch(e){console.log("REJECTED: "+e.message.split("\n")[0])}' \
/tmp/repro-skills/gstack/SKILL.md
Real output
Before (current main, base commit for this report 6042f6a, VERSION 1.98.0.0):
REJECTED: Nested mappings are not allowed in compact mappings at line 2, column 14:
description: Use to review a diff or PR, debug a bug or failing test, QA test a…
^
After quoting the same value with toYamlInlineScalar (PR linked below):
OK name=gstack descLen=229
The description parses back to exactly ROUTER_DESCRIPTION, so nothing is lost or rewritten — only the encoding changes.
Expected
Frontmatter written by gstack-harness register parses as YAML for every target, including harnesses that use a strict loader (Pi, QM), and the register output is a skill the harness actually lists.
Impact
--skills-dir registration with generic produces a skill that YAML-strict harnesses never load. Pi is the case I hit; ~/.agents/skills is Pi's documented skill location, so the natural install path is exactly this one. --context / --print are unaffected (no frontmatter), and the Claude/Codex/Cursor/Gemini routers are unaffected (their committed description has no colon).
Interim workaround: after register, quote the value by hand (description: "<text>"), or register a --context block instead. Both are overwritten by the next register / --refresh-registered.
Readiness report
doctor (paths shortened to ~; 2 warns and 1 not-configured are unrelated to this issue)
gstack doctor 1.98.0.0
ok install root ~/.claude/skills/gstack: opencode global current (1.98.0.0), cursor global current (1.98.0.0), agy global current (1.98.0.0), gemini global current (1.98.0.0), codex global current (1.98.0.0), claude global current (1.98.0.0)
ok rescue refs none in ~/.claude/skills/gstack
ok state root ~/.gstack durable=yes (selected by default)
ok bun 1.4.2 at ~/.bun/bin/bun (floor 1.3.3, tested 1.4.2)
ok hooks 15 hook(s) parse
ok windows bash C:/Program Files/Git/bin/bash.exe (chosen by git --exec-path)
ok codex codex-cli 0.166.0; self-locate ok
warn codex probe not probed; Codex readiness is unverified until a skill or --live runs it
not configured artifacts sync off; cross-machine artifacts sync is unavailable
ok browse bundle browse/dist built
ok binaries find-browse, design, pdf, gstack-global-discover launch (4 of 4)
ok cso native helper 1.98.0.0
ok claude code 2.1.319 (Claude Code)
ok session journal no session journals for this project
ok guard log no guard decisions logged
13 ok, 2 warn, 1 not configured, 0 fail
Environment
- Host:
generictarget (Pi 0.x, skills root~/.agents/skills), also affects any harness with a strict YAML frontmatter loader - OS: Windows 11, Git for Windows bash, Bun 1.4.2, Node v26.12.1
- gstack: VERSION
1.98.0.0installed; reproduced onmainat6042f6ad48774504f918ab1391908c1ccdb11fe0
Fix: PR to follow (extracts toYamlInlineScalar into lib/yaml-scalar.ts, uses it at both harness-register.ts emission sites, with tests).
- Dominant language
- TypeScript
- Stars
- 139k
- Forks
- 20.6k
- Avg merge
- 10h 12m
- Merged PRs (30d)
- 655
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from garrytan/gstack
-
Difficulty 2/5 1-3 hours Newbie friendliness 77/100
Maintainers usually reply within 1 day
-
/codex: the filesystem boundary's bare `agents/` makes Codex skip a repository's own agents/ folderPossibly taken A pull request linked to this issue is open or already merged. Openbug S3
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
Maintainers usually reply within 1 day
-
S3
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
bug
Difficulty 1/5 Under an hour Newbie friendliness 70/100
garrytan/gstack#3091 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 24/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
backnotprop/plannotator#2914 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
microsoft/vscode-containers#655 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
dsh-tauri-desk/deepseek-harness-desktop#1477 · 1 comment ·
-
[docs] RELEASE.md: wrong branch name, no check that the prepare PR merged with the right subject, manual publish stepPossibly taken @albertteoh claimed this today. Opendocumentation
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
jaegertracing/jaeger-ui#4739 ·
Maintainers usually reply within 1 day