Skip to content

feat(site): agent contract in llms.txt + FAQ/AEO with drift guards#229

Merged
ktn-jamf merged 3 commits into
mainfrom
worktree-llms-agent-contract
May 31, 2026
Merged

feat(site): agent contract in llms.txt + FAQ/AEO with drift guards#229
ktn-jamf merged 3 commits into
mainfrom
worktree-llms-agent-contract

Conversation

@ktn-jamf
Copy link
Copy Markdown
Collaborator

Why

Make jamf-cli more discoverable and usable by LLM agents and answer engines (ChatGPT/Claude/Perplexity/Google AI), and make the new hand-authored content self-defending against drift. The CLI was already strong here (structured output, exit codes, commands -o json, an existing llms.txt/commands.json, an AI-crawler allowlist, schema.org JSON-LD) — this closes the remaining gaps.

What

llms.txt — agent operating contract

  • New ## For AI Agents section: runtime discovery (commands -o json), unattended flags (--no-input/--quiet/JAMF_CLI_ARGS), the exit-code table + JSON error envelope, token-efficiency flags, and apply/destructive semantics.
  • Expanded Output Formats (--select/--field/--compact, the 50-row hint).

Site AEO (docs/site)

  • Visible FAQ section + matching FAQPage JSON-LD (shared Q&A text).
  • meta robots (max-snippet:-1, max-image-preview:large).
  • Freshness signals: JSON-LD dateModified/softwareVersion, sitemap <lastmod>, and a self-updating command count in the OG/Twitter meta — all stamped at deploy from commands.json (fixes a stale 1,2511,299).

Version parsing fix

  • generator/site parseVersion now reads the JSON version field (the version command defaults to -o json), with a plain-text fallback. Previously commands.json/llms.txt/version badges could record version "unknown".

Drift guards — staleness fails CI loudly instead of rotting silently:

  • Exit-code table in llms.txtinternal/exitcode (Go unit test).
  • FAQ questions ↔ FAQPage JSON-LD (verify-site-output.sh).
  • llms.txt flag names must exist in the CLI (--help globals ∪ commands.json flags).
  • Every product in commands.json must be documented in llms.txt + FAQ.
  • FAQ "over N commands" floor must not exceed the real count.

How it was verified

  • make verify-site-output — all checks green, including the new flag/product/count guards.
  • Both new guards proven to fail on injected drift (--bogus-flag; over 99999 commands), and the exit-code guard proven to fail on a renumbered code.
  • Deploy stamp simulated end-to-end: placeholders resolve to valid JSON/XML (softwareVersion=…, dateModified=…, count → 1,299), with a guard that fails the deploy if any placeholder survives.
  • FAQ rendering reviewed in light + dark mode.

Notes for reviewers

  • __VERSION__ / __BUILD_DATE__ / __COMMAND_COUNT__ are intentional placeholders committed in index.html/sitemap.xml; the Stamp build freshness step in deploy-site.yaml substitutes them in the throwaway runner checkout. Locally they appear unsubstituted in <head>/sitemap (invisible on the page).
  • The FAQ keeps "over 1,250 commands" as a deliberately rounded, guarded floor rather than a stamped exact number, so local previews don't show a placeholder in visible text.
  • Irreducible gap: free prose (install syntax, auth-method wording) still needs human review — no guard can verify a sentence is true.

🤖 Generated with Claude Code

ktn-jamf and others added 3 commits May 31, 2026 09:29
Make jamf-cli more discoverable and usable by LLM agents and answer
engines, and guard the new hand-authored content against drift.

llms.txt:
- Add a "For AI Agents" operating contract: runtime discovery via
  `commands -o json`, unattended flags, the exit-code table + JSON error
  envelope, token-efficiency flags, and apply/destructive semantics.
- Expand Output Formats (--select/--field/--compact, 50-row hint).
- Guard the exit-code table against internal/exitcode (unit test).

Site AEO (docs/site):
- Add a visible FAQ section + matching FAQPage JSON-LD (shared text).
- Add meta robots (max-snippet/max-image-preview).
- Freshness signals: JSON-LD dateModified/softwareVersion and sitemap
  <lastmod>, plus a self-updating command count in the OG/Twitter meta,
  stamped at deploy from commands.json (fixes a stale 1,251 -> 1,299).

Version parsing fix:
- generator/site parseVersion now reads the JSON `version` field (the
  `version` command defaults to -o json), with a plain-text fallback;
  previously commands.json/llms.txt could record version "unknown".

Drift guards (verify-site-output.sh):
- FAQ questions must match between the visible section and FAQPage.
- llms.txt flag names must exist in the CLI (--help globals plus
  commands.json per-command flags).
- Every product in commands.json must be documented in llms.txt + FAQ.
- The FAQ "over N commands" floor must not exceed the real count.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Resolve conflict in generator/site/main.go. main's #227 landed an equivalent
"parse version from JSON" fix (extractRawVersion) that also trims the bare
"-dirty" marker — strictly more complete than this branch's rawVersion, which
missed the clean-tag-built-on-dirty-tree case. Kept main's extractRawVersion +
parseVersion; dropped the branch's redundant rawVersion.

The branch's real contribution (llms.txt "For AI Agents" contract + Output
Formats expansion in renderLLMSTxt) auto-merged cleanly. Both branches'
parseVersion JSON test cases were retained as complementary coverage.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address PR review nits:

- verify-site-output.sh: the FAQ<->FAQPage guard now also compares answer
  text (acceptedAnswer.text vs the visible <p>), not just question text.
  Google's FAQ structured-data policy requires the markup answer to match
  the visible answer; question-only parity let answers drift silently. Tags
  are stripped, HTML entities decoded, and whitespace normalized before
  comparing. Verified to fail on an injected visible-answer change and pass
  on the in-sync content.

- site-preflight.yaml: pass --binary ./bin/jamf-cli to verify-site-output.sh
  so the llms.txt flag-name guard runs on the release-tag preflight path too
  (previously only ci.yaml's make target exercised it; the binary is already
  built one step earlier).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ktn-jamf ktn-jamf marked this pull request as ready for review May 31, 2026 15:56
@ktn-jamf ktn-jamf enabled auto-merge (squash) May 31, 2026 15:56
@ktn-jamf ktn-jamf merged commit 9e9f6d3 into main May 31, 2026
2 checks passed
@ktn-jamf ktn-jamf deleted the worktree-llms-agent-contract branch May 31, 2026 17:24
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.

2 participants