@softspark/ai-toolkit 3.1.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/AGENTS.md CHANGED
@@ -348,7 +348,7 @@ Security expert. Use for OWASP Top 10, CVE analysis, security audits, penetratio
348
348
 
349
349
  ### `seo-specialist`
350
350
 
351
- Search engine optimization specialist. Trigger words: SEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org
351
+ Search engine + generative engine optimization specialist. Trigger words: SEO, GEO, AEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org, llms.txt, ChatGPT visibility, Claude citation, Perplexity ranking, AI Overviews
352
352
 
353
353
  **Tools:** `Read, Write, Edit, Bash, Grep, Glob`
354
354
 
@@ -436,7 +436,7 @@ Specialized agent personas — apply their expertise for relevant tasks:
436
436
  - **search-specialist**: Information retrieval and search optimization specialist. Trigger words: search, query, semantic search, information retrieval, relevance, ranking, search optimization
437
437
  - **security-architect**: Proactive security design expert. Use for Threat Modeling, architecture security reviews, and designing secure systems (AuthN/AuthZ, Crypto).
438
438
  - **security-auditor**: Security expert. Use for OWASP Top 10, CVE analysis, security audits, penetration testing, vulnerability assessment, hardening. Triggers: security, owasp, cve, vulnerability, audit, hardening, penetration, pentest, injection test, api security.
439
- - **seo-specialist**: Search engine optimization specialist. Trigger words: SEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org
439
+ - **seo-specialist**: Search engine + generative engine optimization specialist. Trigger words: SEO, GEO, AEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org, llms.txt, ChatGPT visibility, Claude citation, Perplexity ranking, AI Overviews
440
440
  - **system-governor**: The Guardian of the Constitution. Validates all evolutionary changes and enforces immutable rules. Has VETO power.
441
441
  - **tech-lead**: Technical authority for code quality, architecture patterns, and stack decisions. Use for code reviews, technological disputes, and standards enforcement.
442
442
  - **technical-researcher**: Deep technical investigation and multi-source research synthesis specialist. Trigger words: technical research, feasibility study, root cause analysis, API investigation, compatibility research, comparison matrix, synthesize, aggregate, report, executive summary, gap analysis, findings, multi-source, cross-reference
@@ -454,7 +454,7 @@ Skills are invocable commands or auto-loaded knowledge sources:
454
454
  - **architecture-audit**: Explore codebase organically for architectural friction, discover shallow modules, and propose module-deepening refactors as GitHub issue RFCs using parallel sub-agent interface designs. Use when user wants to improve architecture, find shallow modules, deepen modules, or reduce coupling. Codex-adapted: uses native subagents and plan tracking.
455
455
  - **architecture-decision**: Architecture decision making via trade-off analysis in RFC/RFD/ADR format: context, constraints, 3+ options, comparison, recommendation. Triggers: architecture decision, ADR, RFC, RFD, trade-offs, options comparison, design choice, pick between, should we use, evaluate approach. Load when weighing 2+ architectural options or writing decision records.
456
456
  - **biz-scan**: Scans codebase for business opportunities by analyzing database schemas, API endpoints, tracking events, and feature flags to surface underutilized capabilities, missing KPIs, and monetization gaps. Use when the user asks about revenue opportunities, business metrics, KPI coverage, analytics gaps, or monetization analysis of a codebase.
457
- - **brand-voice**: Loaded when writing documentation, content, README, or user-facing text. Prevents generic LLM rhetoric and enforces direct, technical voice.
457
+ - **brand-voice**: Loaded when writing documentation, content, README, or user-facing text, AND when an output-mode is set for conversational responses. Prevents generic LLM rhetoric, enforces direct technical voice, and supplies optional concise/strict response modes.
458
458
  - **briefing**: Generate an executive daily briefing that aggregates reports from all agents into a short, decision-focused summary. Use when the user asks for a status update across the whole system — not for one-agent activity reports.
459
459
  - **build**: Build the project with auto-detected toolchain (npm, poetry, cargo, go, flutter, Docker). Use when the user asks to compile, bundle, or produce artifacts — not to run tests or deploy.
460
460
  - **chaos**: Inject controlled faults for resilience testing on non-production targets. Use when the user explicitly asks for a chaos experiment, latency injection, or dependency kill — never implicit.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,48 @@ Versioning follows [Semantic Versioning](https://semver.org/).
7
7
 
8
8
  ---
9
9
 
10
+ ## v3.2.0 — Output discipline & token-aware status line (2026-05-04)
11
+
12
+ Minor release. Two coordinated additions: per-response output discipline and a real-token status line installed by default.
13
+
14
+ ### Added
15
+
16
+ - **`brand-voice` output modes** — `concise` (≤60% tokens) and `strict` (≤40% tokens) extend the existing brand-voice skill with response-length governance. Activate via `output-mode: concise` in project `CLAUDE.md` or `/brand-voice concise`. Mode rules in `app/skills/brand-voice/modes/`.
17
+ - **`measure.py` token evaluator** — fixture-driven before/after comparison at `app/skills/brand-voice/scripts/measure.py`. Asserts budget compliance and load-bearing fact preservation via optional `must_contain.txt` per fixture. JSON and human report formats.
18
+ - **`session_token_stats.py`** — stdlib-only Claude Code session JSONL parser at `scripts/session_token_stats.py`. Reports real input/output/cache token counts per session, supports `--since`, `--baseline`, `--statusline`, and `--json` modes.
19
+ - **Comprehensive default status line** — new `app/hooks/ai-toolkit-statusline.sh` renders a single line with cwd, git branch + dirty marker, context-window as a 10-cell progress bar (green <70% / orange 70–89% / red ≥90%), upload arrow `↑` (input tokens, green) + download arrow `↓` (output tokens, red), effort level, and model name. All token + cost data is read directly from Claude Code's statusLine stdin (`context_window.total_input_tokens`, `total_output_tokens`, `cost.total_cost_usd`, `effort.level`) — no JSONL parsing in the hot path, ~50ms cold start. Installed automatically into `~/.claude/settings.json` by `ai-toolkit install` (and `update`). User-customized statusLine entries (without the ai-toolkit `_source` tag) are preserved untouched. Cost-estimate segment is opt-in via `AI_TOOLKIT_STATUSLINE_SHOW_COST=1`.
20
+ - **`merge-hooks.py` statusLine support** — `inject` writes the toolkit statusLine only when the target has none or has a stale toolkit-installed one. `strip` removes only toolkit-installed entries.
21
+ - **`briefing` skill `--tokens` mode** — `/briefing --tokens [--since 7d]` for explicit reporting and baseline capture. Includes wire-up docs for the status-line hook and `AI_TOOLKIT_STATUSLINE_*` opt-out env vars.
22
+ - **Hook runtime scripts deployed alongside hooks** — `scripts/install_steps/hooks.py` now copies a curated allowlist of Python helpers (`session_token_stats.py`, `version_check.py`) to `~/.softspark/ai-toolkit/scripts/`, so hooks work on a fresh install before the npm-global package catches up. Hook resolution order: `AI_TOOLKIT_DIR` → `~/.softspark/ai-toolkit/` → npm global → walk up from script (dev fallback).
23
+
24
+ ### Opt-out
25
+
26
+ - `AI_TOOLKIT_STATUSLINE_DISABLE=1` silences output entirely
27
+ - `AI_TOOLKIT_STATUSLINE_NO_TOKENS=1` hides token arrows segment
28
+ - `AI_TOOLKIT_STATUSLINE_NO_GIT=1` hides git segment
29
+ - `AI_TOOLKIT_STATUSLINE_NO_EFFORT=1` hides effort level segment
30
+ - `AI_TOOLKIT_STATUSLINE_NO_COLOR=1` disables ANSI colors
31
+ - `AI_TOOLKIT_STATUSLINE_SHOW_COST=1` appends Claude Code's reported `cost.total_cost_usd` (off by default — long Opus sessions show alarming numbers)
32
+ - `AI_TOOLKIT_STATUSLINE_DUMP=1` writes received stdin to `/tmp/cc-statusline-input.json` (debug only)
33
+
34
+ ### Tests
35
+
36
+ - 38 new bats tests across `tests/test_brand_voice.bats`, `tests/test_session_token_stats.bats`, `tests/test_statusline_hook.bats`, `tests/test_merge_hooks_statusline.bats`, plus install-step assertion in `tests/test_install.bats`.
37
+
38
+ ---
39
+
40
+ ## v3.1.1 — Windows install fix (2026-04-29)
41
+
42
+ Patch release. `ai-toolkit install --local` crashed on Windows before doing any work because `scripts/install_steps/project_registry.py` imported `fcntl` (POSIX-only) at module load, raising `ModuleNotFoundError: No module named 'fcntl'`.
43
+
44
+ ### Fixed
45
+
46
+ - **Windows install crash** — `project_registry` now imports `fcntl` and `msvcrt` defensively (try/except → `None`) and `_registry_lock()` selects between `fcntl.flock` (POSIX) and `msvcrt.locking` (Windows) at runtime. POSIX semantics unchanged; Windows acquires the lock with `LK_NBLCK` + 30 s deadline + 10 ms retry backoff.
47
+
48
+ ### Added
49
+
50
+ - **Windows compat regression test** — `tests/test_windows_support.bats` now blocks `import fcntl` via a custom `meta_path` finder, stubs `msvcrt`, and forces the Windows branch of `_registry_lock` so future regressions are caught on the POSIX CI runners without needing a Windows machine.
51
+
10
52
  ## v3.1.0 — Global Editor Install Alignment (2026-04-28)
11
53
 
12
54
  Minor release aligning global and project-local editor configuration with the current documented surfaces for all supported editors.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
7
7
  [![Skills](https://img.shields.io/badge/skills-112-brightgreen)](app/skills/)
8
8
  [![Agents](https://img.shields.io/badge/agents-44-blue)](app/agents/)
9
- [![Tests](https://img.shields.io/badge/tests-973%20passing-success)](tests/)
9
+ [![Tests](https://img.shields.io/badge/tests-1038%20passing-success)](tests/)
10
10
 
11
11
  <p align="center">
12
12
  <img src="assets/ai-toolkit-readme-hero.png" alt="ai-toolkit 3 README hero showing one toolkit for 12 AI editors" width="900">
@@ -14,33 +14,14 @@
14
14
 
15
15
  ---
16
16
 
17
- ## What's New in v3.1.0
17
+ ## What's New in v3.2.0
18
18
 
19
- **3.1.0 aligns global and project-local editor installs** with the current documented config surfaces for all 12 supported tools.
19
+ Minor release adding response-length governance and a token-aware status line installed by default.
20
20
 
21
- - `ai-toolkit install --editors cline` now writes documented global rules under `~/Documents/Cline/Rules/`.
22
- - `ai-toolkit install --editors roo` now writes documented global rules under `~/.roo/rules/`.
23
- - `ai-toolkit install --editors aider` safely creates `~/.aider.conf.yml` only when absent and refreshes `~/.aider-ai-toolkit-CONVENTIONS.md`.
24
- - Roo Code now has project MCP sync via `.roo/mcp.json` from the canonical `.mcp.json`.
25
- - Cursor rules are explicitly project-local; Cursor MCP remains supported at project/global scope through `.cursor/mcp.json`.
26
-
27
- ### Carried from v3.0.0 (feature release)
28
-
29
- - **Deep coverage: every editor at 100% of its native surface.** New generators emit hooks, sub-agents, custom commands, and skill pointers per editor: `generate_cursor_agents.py`, `generate_cursor_hooks.py`, `generate_windsurf_hooks.py`, `generate_gemini_commands.py`, `generate_gemini_hooks.py`, `generate_gemini_skills.py`, `generate_augment_agents.py`, `generate_augment_commands.py`, `generate_augment_hooks.py`, `generate_augment_skills.py`, `generate_codex_skills.py`.
30
- - **`--profile full`** turns on every native surface across all supported editors in one flag. `minimal` / `standard` / `strict` retain prior semantics but `standard` now also wires Gemini hooks and the Copilot directory layout (see Breaking Changes).
31
- - **Codex skill mirroring** uses Codex's native `.agents/skills/` discovery path. `--editors codex` installs translated skills there; `--codex-skills` explicitly refreshes the same catalog.
32
- - **58 new bats tests** covering native surface generators plus per-editor suites for aider, antigravity, augment, claude-code, cline, codex, copilot, cursor, gemini, opencode, roo, windsurf.
33
- - **Skill quality pass** (folded in from the 2.12 work that is now skipped): 62 skills upgraded to 4-5 / 5 on the meta-architect audit; `add_gotcha` added as a fifth mutation strategy.
34
-
35
- ### Breaking changes (from 3.0.0)
36
-
37
- - `--profile standard` now installs **Gemini hooks** automatically. To opt out, use `--profile minimal` or pass `--skip gemini-hooks`.
38
- - Copilot now uses the **directory layout** (`.github/copilot/`) instead of a single monolithic file. Existing single-file installs are preserved but new installs emit the directory form.
39
- - `2.13.0` is skipped. Upgrade path is `2.12.x` → `3.0.0`.
40
-
41
- ### Non-breaking additions (opt-in)
42
-
43
- - `.windsurf/hooks.json`, `.cursor/hooks.json`, `.cursor/agents/`, `.augment/agents/`, `.augment/commands/`, and `.gemini/commands/` are **only emitted when you opt in** via `--profile full`. Codex skills are emitted under `.agents/skills/` whenever the Codex editor target is selected, matching Codex's native discovery path.
21
+ - **Output modes for `brand-voice`** `concise` (≤60% tokens) and `strict` (≤40%) modes governing conversational responses, with rule files in `app/skills/brand-voice/modes/` and a `measure.py` evaluator that runs against fixtures with load-bearing-fact assertions.
22
+ - **Default comprehensive status line** — `ai-toolkit install` now wires `~/.claude/settings.json` to a single line showing cwd, git, a 10-cell context-window progress bar (green <70% / orange 70–89% / red ≥90%), `↑input ↓output` token arrows, effort level, and model. All data read directly from Claude Code's statusLine stdin — no JSONL parsing, ~50 ms cold start. User-customized statusLine entries are preserved untouched. Cost segment opt-in via `AI_TOOLKIT_STATUSLINE_SHOW_COST=1`.
23
+ - **Real token telemetry** `scripts/session_token_stats.py` parses Claude Code session JSONL for `/briefing --tokens` reporting and baseline capture. Stdlib-only.
24
+ - **Opt-outs via env vars** `AI_TOOLKIT_STATUSLINE_DISABLE`, `_NO_TOKENS`, `_NO_GIT`, `_NO_EFFORT`, `_NO_COLOR`, `_SHOW_COST` (opt-in), `_DUMP` (debug).
44
25
 
45
26
  See [CHANGELOG.md](CHANGELOG.md) for full history.
46
27
 
@@ -147,8 +128,8 @@ See [CLI Reference](kb/reference/cli-reference.md) for all commands and options.
147
128
  | Component | Count | Description |
148
129
  |-----------|-------|-------------|
149
130
  | `skills/` (task) | 32 | Slash commands: `/commit`, `/build`, `/deploy`, `/test`, `/mcp-builder`, ... |
150
- | `skills/` (hybrid) | 31 | Slash commands with agent knowledge base |
151
- | `skills/` (knowledge) | 49 | Domain knowledge auto-loaded by agents (includes 13 `<lang>-rules` skills) |
131
+ | `skills/` (hybrid) | 32 | Slash commands with agent knowledge base |
132
+ | `skills/` (knowledge) | 48 | Domain knowledge auto-loaded by agents (includes 13 `<lang>-rules` skills) |
152
133
  | `agents/` | 44 | Specialized agents across 10 categories |
153
134
  | `hooks/` | 21 global + 5 skill-scoped | Quality gates, path safety, prompt governance, session lifecycle |
154
135
  | `plugins/` | 11 packs | Opt-in domain bundles (security, research, frontend, enterprise, 6 language packs) |
@@ -173,7 +154,7 @@ ai-toolkit/
173
154
  │ └── ARCHITECTURE.md # Full system design
174
155
  ├── kb/ # Reference docs, procedures, plans
175
156
  ├── scripts/ # Validation, install, evaluation scripts
176
- ├── tests/ # Bats test suite (973 tests)
157
+ ├── tests/ # Bats test suite (1038 tests)
177
158
  └── CHANGELOG.md
178
159
  ```
179
160
 
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-toolkit",
3
3
  "description": "Professional-grade Claude Code toolkit with persona presets, skill security auditor, expanded lifecycle hooks, experimental opt-in plugin packs, benchmark harvesting, and multi-tool support.",
4
- "version": "3.1.0",
4
+ "version": "3.2.0",
5
5
  "author": {
6
6
  "name": "SoftSpark",
7
7
  "url": "https://github.com/softspark"
@@ -12,6 +12,53 @@ Universal multi-agent system for software development. Works across all reposito
12
12
 
13
13
  ---
14
14
 
15
+ ## Layered Model (the five-layer mental model)
16
+
17
+ The toolkit is organised as five stacked layers. Higher layers depend on lower layers, never the other way around. Treat this as the canonical mental model when adding features — pick the lowest layer that fits.
18
+
19
+ ```
20
+ ┌─────────────────────────────────────────────────────────────┐
21
+ │ Layer 5 — Plugins (distribution) │
22
+ │ Bundles for npm / marketplace / ai-toolkit eject │
23
+ │ Files: app/plugins/, plugin.json, package.json │
24
+ ├─────────────────────────────────────────────────────────────┤
25
+ │ Layer 4 — Subagents (delegation) │
26
+ │ Specialised personas spawned via Agent / Teams │
27
+ │ Files: app/agents/, .claude/agents/ │
28
+ ├─────────────────────────────────────────────────────────────┤
29
+ │ Layer 3 — Hooks (the guardrail layer) │
30
+ │ Lifecycle events: SessionStart, PreToolUse, Stop, … │
31
+ │ Files: app/hooks/*.sh, settings.json hooks block │
32
+ ├─────────────────────────────────────────────────────────────┤
33
+ │ Layer 2 — Skills (the knowledge layer) │
34
+ │ Slash-commands, knowledge skills, hybrid skills │
35
+ │ Files: app/skills/<name>/SKILL.md │
36
+ ├─────────────────────────────────────────────────────────────┤
37
+ │ Layer 1 — CLAUDE.md (the memory layer) │
38
+ │ Persistent rules + auto-memory loaded into every session │
39
+ │ Files: CLAUDE.md (global / project / .claude) │
40
+ └─────────────────────────────────────────────────────────────┘
41
+ ```
42
+
43
+ ### Where does my new feature go?
44
+
45
+ | If the feature is… | Add it at | Examples |
46
+ |---|---|---|
47
+ | A persistent rule the model must always know | Layer 1 (CLAUDE.md) | "always sync_tasks first", commit conventions |
48
+ | A reusable workflow / domain knowledge | Layer 2 (Skills) | `/debug`, `/review`, `python-rules` |
49
+ | Behavior the harness must enforce automatically | Layer 3 (Hooks) | block destructive `rm -rf`, run lint on Stop |
50
+ | A specialised role for delegation | Layer 4 (Subagents) | `security-auditor`, `database-architect` |
51
+ | A shippable bundle for other repos | Layer 5 (Plugins) | `app/plugins/python-stack/` |
52
+
53
+ ### Cross-cutting rules
54
+
55
+ - A skill MAY trigger an agent (`agent: <name>` frontmatter) — that's Layer 2 calling Layer 4.
56
+ - A hook MUST NOT call a skill — hooks are deterministic shell, skills are LLM-driven.
57
+ - A plugin MAY bundle skills + agents + hooks, but never the inverse.
58
+ - CLAUDE.md is read by every layer; it is the only layer everyone reads.
59
+
60
+ ---
61
+
15
62
  ## Agents
16
63
 
17
64
  ### Orchestration & Planning (4)
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  name: seo-specialist
3
- description: "Search engine optimization specialist. Trigger words: SEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org"
3
+ description: "Search engine + generative engine optimization specialist. Trigger words: SEO, GEO, AEO, search engine, meta tags, structured data, Core Web Vitals, sitemap, robots.txt, schema.org, llms.txt, ChatGPT visibility, Claude citation, Perplexity ranking, AI Overviews"
4
4
  tools: Read, Write, Edit, Bash, Grep, Glob
5
5
  model: sonnet
6
6
  color: cyan
7
7
  skills: clean-code, seo-validate
8
8
  ---
9
9
 
10
- # SEO Specialist
10
+ # SEO + GEO Specialist
11
11
 
12
- Search engine optimization specialist.
12
+ Optimization for both classical search engines AND generative engines (ChatGPT, Claude, Perplexity, Google AI Overviews, Gemini).
13
13
 
14
14
  ## Expertise
15
15
  - Technical SEO
@@ -17,6 +17,7 @@ Search engine optimization specialist.
17
17
  - Core Web Vitals
18
18
  - Structured data (Schema.org)
19
19
  - SEO auditing
20
+ - **Generative Engine Optimization (GEO)** — being cited by LLM-based answer engines
20
21
 
21
22
  ## Responsibilities
22
23
 
@@ -108,4 +109,86 @@ Sitemap: https://example.com/sitemap.xml
108
109
  ```python
109
110
  smart_query("SEO optimization patterns")
110
111
  hybrid_search_kb("technical SEO checklist")
112
+ smart_query("GEO generative engine optimization")
111
113
  ```
114
+
115
+ ---
116
+
117
+ ## Generative Engine Optimization (GEO)
118
+
119
+ Goal: get cited by ChatGPT, Claude, Perplexity, Gemini, and Google AI Overviews — not just rank in classical SERPs.
120
+
121
+ ### When to use SEO vs GEO
122
+ - **SEO**: a user types a query and clicks a link → optimise for click-through.
123
+ - **GEO**: a user asks an LLM and reads the synthesis → optimise for **inclusion in the answer + named source attribution**.
124
+ - They overlap on technical foundations (crawlability, structured data, authority) and diverge on content shape and citability.
125
+
126
+ ### Citability checklist (the 12 things LLM crawlers reward)
127
+ 1. **One claim per sentence.** LLMs extract sentence-level snippets — long compound sentences get dropped.
128
+ 2. **Lead with the answer.** Inverted-pyramid structure — definition / number / decision in the first sentence of each section.
129
+ 3. **Stable, descriptive H2/H3 headings phrased as questions.** Mirrors how users prompt LLMs.
130
+ 4. **Unique data, numbers, dates, version strings.** Verifiable facts get cited; opinion does not.
131
+ 5. **Named author + author bio with credentials.** Authority signal that survives synthesis.
132
+ 6. **Original quotes from named experts.** Quotation blocks are over-represented in LLM citations.
133
+ 7. **Comparison tables with explicit labels.** Tables are extracted whole; vague prose is summarised away.
134
+ 8. **Schema.org `Article`, `FAQPage`, `HowTo`, `QAPage`, `Person`.** Mandatory for entity disambiguation.
135
+ 9. **`llms.txt` at site root.** Curated index of canonical pages for LLM crawlers (Anthropic-proposed convention).
136
+ 10. **Stable URLs with semantic slugs.** LLMs cache citations — URL changes erase your authority overnight.
137
+ 11. **Cross-linking with descriptive anchors.** "this article" is dead anchor text; use the actual claim.
138
+ 12. **Date stamps on every page.** Recency is a top-3 ranking factor for AI Overviews and Perplexity.
139
+
140
+ ### `llms.txt` template
141
+ ```
142
+ # Brand Name
143
+ > One-sentence description of what the site is and who it's for.
144
+
145
+ ## Core docs
146
+ - [Title](/url): one-line summary the LLM should remember
147
+ - [Title](/url): one-line summary
148
+
149
+ ## API reference
150
+ - [Endpoint](/url): purpose, auth, response shape
151
+
152
+ ## Optional
153
+ - [Changelog](/changelog): recent updates
154
+ ```
155
+
156
+ ### GEO audit checklist
157
+ - [ ] First sentence of every page answers the page's title as a question
158
+ - [ ] At least one comparison table OR numbered list per long-form page
159
+ - [ ] Author block with name + role + LinkedIn / GitHub / ORCID
160
+ - [ ] Schema.org `Article` with `author`, `datePublished`, `dateModified`
161
+ - [ ] Schema.org `FAQPage` for any page with Q/A structure
162
+ - [ ] `llms.txt` at site root with curated canonical URLs
163
+ - [ ] Page contains at least 3 unique data points (numbers, dates, version strings)
164
+ - [ ] Date visible to the user, not just in metadata
165
+ - [ ] No paywall / login wall on indexable content
166
+ - [ ] No JavaScript-only content for primary value (LLM crawlers often skip JS)
167
+ - [ ] Internal links use claim-as-anchor, not "click here"
168
+ - [ ] Brand and product names are consistent across the entire site
169
+
170
+ ### Measuring GEO outcomes
171
+ GEO has no Search Console equivalent. Substitutes:
172
+ - **Manual prompt testing**: query each target prompt monthly in ChatGPT / Claude / Perplexity / AI Overviews; record whether your domain appears in the citation footer.
173
+ - **Referrer analysis**: filter analytics by `Referer` containing `chat.openai.com`, `perplexity.ai`, `claude.ai`, `gemini.google.com`.
174
+ - **Brand-mention monitoring**: tools that scrape LLM outputs for mentions (Otterly, Profound, AthenaHQ).
175
+ - **Server logs**: identify and welcome crawler user-agents (`GPTBot`, `ClaudeBot`, `PerplexityBot`, `Google-Extended`, `OAI-SearchBot`).
176
+
177
+ ### `robots.txt` for AI crawlers (allow by default)
178
+ ```
179
+ User-agent: GPTBot
180
+ Allow: /
181
+
182
+ User-agent: ClaudeBot
183
+ Allow: /
184
+
185
+ User-agent: PerplexityBot
186
+ Allow: /
187
+
188
+ User-agent: Google-Extended
189
+ Allow: /
190
+
191
+ User-agent: OAI-SearchBot
192
+ Allow: /
193
+ ```
194
+ Disallow only what you would disallow for Googlebot. Blocking AI crawlers wholesale erases you from generative answers — the trade-off is rarely worth it for content sites.
@@ -0,0 +1,201 @@
1
+ #!/usr/bin/env bash
2
+ # ai-toolkit-statusline.sh — comprehensive Claude Code status line.
3
+ #
4
+ # Renders one line. Left side: cwd, git, ctx%, i/o token split.
5
+ # Right side (right-aligned): effort level, model name.
6
+ # Optional cost segment is opt-in via AI_TOOLKIT_STATUSLINE_SHOW_COST=1.
7
+ #
8
+ # All token + cost data is read directly from Claude Code's statusLine stdin
9
+ # (context_window.total_input_tokens, total_output_tokens, cost.total_cost_usd,
10
+ # effort.level). No JSONL parsing in the hot path.
11
+ #
12
+ # Wire-up: ai-toolkit installer adds this as default `statusLine` in
13
+ # ~/.claude/settings.json. Manual config:
14
+ # {
15
+ # "statusLine": {
16
+ # "type": "command",
17
+ # "command": "bash ~/.softspark/ai-toolkit/hooks/ai-toolkit-statusline.sh"
18
+ # }
19
+ # }
20
+ #
21
+ # Env vars (all optional):
22
+ # AI_TOOLKIT_DIR — toolkit install location (auto-detected)
23
+ # AI_TOOLKIT_STATUSLINE_DISABLE — "1" silences output entirely
24
+ # AI_TOOLKIT_STATUSLINE_NO_COLOR — "1" disables ANSI colors
25
+ # AI_TOOLKIT_STATUSLINE_NO_TOKENS — "1" hides i/o segment
26
+ # AI_TOOLKIT_STATUSLINE_NO_GIT — "1" hides git segment
27
+ # AI_TOOLKIT_STATUSLINE_NO_EFFORT — "1" hides effort segment
28
+ # AI_TOOLKIT_STATUSLINE_SHOW_COST — "1" appends Claude Code's reported cost
29
+ # AI_TOOLKIT_STATUSLINE_DUMP — "1" writes stdin to /tmp/cc-statusline-input.json
30
+ #
31
+ # Performance: ~50ms (single python3 parse of stdin, one git invocation).
32
+
33
+ set -u
34
+
35
+ [ "${AI_TOOLKIT_STATUSLINE_DISABLE:-0}" = "1" ] && exit 0
36
+
37
+ # ── Colors ───────────────────────────────────────────────────────────────────
38
+ # Claude Code captures stdout via pipe but interprets ANSI escapes when it
39
+ # renders the statusline. So always emit colors unless explicitly disabled.
40
+ if [ "${AI_TOOLKIT_STATUSLINE_NO_COLOR:-0}" = "1" ]; then
41
+ C_RESET="" C_GREEN="" C_BOLD_GREEN="" C_CYAN="" C_BLUE="" C_RED=""
42
+ C_YELLOW="" C_MAGENTA="" C_DIM="" C_GRAY="" C_BOLD_YELLOW="" C_ORANGE=""
43
+ else
44
+ C_RESET=$'\033[0m'
45
+ C_GREEN=$'\033[0;32m'
46
+ C_BOLD_GREEN=$'\033[1;32m'
47
+ C_CYAN=$'\033[0;36m'
48
+ C_BLUE=$'\033[1;34m'
49
+ C_RED=$'\033[0;31m'
50
+ C_YELLOW=$'\033[0;33m'
51
+ C_BOLD_YELLOW=$'\033[1;33m'
52
+ C_MAGENTA=$'\033[0;35m'
53
+ C_DIM=$'\033[2m'
54
+ C_GRAY=$'\033[0;37m'
55
+ C_ORANGE=$'\033[38;5;208m'
56
+ fi
57
+
58
+ # ── Parse stdin in one python3 invocation ────────────────────────────────────
59
+ INPUT="$(cat 2>/dev/null || true)"
60
+
61
+ if [ "${AI_TOOLKIT_STATUSLINE_DUMP:-0}" = "1" ] && [ -n "$INPUT" ]; then
62
+ printf '%s' "$INPUT" > /tmp/cc-statusline-input.json 2>/dev/null
63
+ fi
64
+
65
+ PARSED="$(printf '%s' "$INPUT" | python3 -c '
66
+ import json, sys
67
+ def get(d, path):
68
+ for k in path.split("."):
69
+ d = d.get(k) if isinstance(d, dict) else None
70
+ if d is None:
71
+ return ""
72
+ return d if d is not None else ""
73
+ def fmt_tokens(n):
74
+ try:
75
+ n = int(n)
76
+ except (TypeError, ValueError):
77
+ return "0"
78
+ if n >= 1000:
79
+ return f"{n/1000:.1f}k"
80
+ return str(n)
81
+ try:
82
+ d = json.loads(sys.stdin.read() or "{}")
83
+ except Exception:
84
+ d = {}
85
+ cwd = get(d, "cwd") or ""
86
+ model = get(d, "model.display_name") or get(d, "model.id") or ""
87
+ ctx_pct = get(d, "context_window.used_percentage")
88
+ in_tok = fmt_tokens(get(d, "context_window.total_input_tokens"))
89
+ out_tok = fmt_tokens(get(d, "context_window.total_output_tokens"))
90
+ cost = get(d, "cost.total_cost_usd")
91
+ try:
92
+ cost_str = f"{float(cost):.2f}" if cost != "" else ""
93
+ except (TypeError, ValueError):
94
+ cost_str = ""
95
+ effort = get(d, "effort.level") or ""
96
+ print(f"{cwd}\t{model}\t{ctx_pct}\t{in_tok}\t{out_tok}\t{cost_str}\t{effort}")
97
+ ' 2>/dev/null)"
98
+
99
+ IFS=$'\t' read -r CWD MODEL_NAME CTX_USED IN_TOK OUT_TOK COST EFFORT <<< "$PARSED"
100
+ [ -z "$CWD" ] && CWD="$PWD"
101
+
102
+ # ── Segment: prompt + dir ────────────────────────────────────────────────────
103
+ DIR_BASENAME="$(basename "$CWD" 2>/dev/null || echo '~')"
104
+ SEG_PROMPT="${C_BOLD_GREEN}\xe2\x9e\x9c${C_RESET} ${C_CYAN}${DIR_BASENAME}${C_RESET}"
105
+
106
+ # ── Segment: git ────────────────────────────────────────────────────────────
107
+ SEG_GIT=""
108
+ if [ "${AI_TOOLKIT_STATUSLINE_NO_GIT:-0}" != "1" ] && \
109
+ git -C "$CWD" rev-parse --git-dir >/dev/null 2>&1; then
110
+ BRANCH="$(git -C "$CWD" -c core.fsmonitor=false symbolic-ref --short HEAD 2>/dev/null)"
111
+ if [ -n "$BRANCH" ]; then
112
+ DIRTY=""
113
+ if git -C "$CWD" -c core.fsmonitor=false status --porcelain 2>/dev/null | grep -q .; then
114
+ DIRTY=" ${C_RED}\xe2\x9c\x97${C_RESET}"
115
+ fi
116
+ SEG_GIT=" ${C_BLUE}git:(${C_RED}${BRANCH}${C_BLUE})${C_RESET}${DIRTY}"
117
+ fi
118
+ fi
119
+
120
+ # ── Segment: context window as progress bar ────────────────────────────────
121
+ # 10-cell bar with usage-shaded color: green <50%, yellow 50-79%, red ≥80%.
122
+ build_ctx_bar() {
123
+ local pct=$1
124
+ local cells=10
125
+ local filled=$(( (pct * cells + 50) / 100 ))
126
+ [ "$filled" -gt "$cells" ] && filled=$cells
127
+ [ "$filled" -lt 0 ] && filled=0
128
+ local color
129
+ if [ "$pct" -ge 90 ]; then
130
+ color="$C_RED"
131
+ elif [ "$pct" -ge 70 ]; then
132
+ color="$C_ORANGE"
133
+ else
134
+ color="$C_GREEN"
135
+ fi
136
+ local bar=""
137
+ local i=0
138
+ while [ "$i" -lt "$filled" ]; do
139
+ bar+="\xe2\x96\x88" # █ FULL BLOCK
140
+ i=$((i+1))
141
+ done
142
+ local empty=""
143
+ while [ "$i" -lt "$cells" ]; do
144
+ empty+="\xe2\x96\x91" # ░ LIGHT SHADE
145
+ i=$((i+1))
146
+ done
147
+ printf '%b' "${color}${bar}${C_DIM}${empty}${C_RESET}"
148
+ }
149
+
150
+ SEG_CTX=""
151
+ if [ -n "$CTX_USED" ]; then
152
+ CTX_INT="$(printf '%.0f' "$CTX_USED" 2>/dev/null || echo "$CTX_USED")"
153
+ case "$CTX_INT" in
154
+ ''|*[!0-9]*) CTX_INT=0 ;;
155
+ esac
156
+ SEG_CTX=" $(build_ctx_bar "$CTX_INT") ${C_DIM}${CTX_INT}%${C_RESET}"
157
+ fi
158
+
159
+ # ── Segment: tokens with up/down arrows ─────────────────────────────────────
160
+ # ↑ green = upload (input tokens sent to model)
161
+ # ↓ red = download (output tokens received from model)
162
+ SEG_TOKENS=""
163
+ if [ "${AI_TOOLKIT_STATUSLINE_NO_TOKENS:-0}" != "1" ] && \
164
+ [ -n "$IN_TOK" ] && [ "$IN_TOK" != "0" -o "$OUT_TOK" != "0" ]; then
165
+ SEG_TOKENS=" ${C_BOLD_GREEN}\xe2\x86\x91${IN_TOK}${C_RESET} ${C_RED}\xe2\x86\x93${OUT_TOK}${C_RESET}"
166
+ if [ "${AI_TOOLKIT_STATUSLINE_SHOW_COST:-0}" = "1" ] && [ -n "$COST" ]; then
167
+ SEG_TOKENS+=" ${C_BOLD_GREEN}\$${COST}${C_RESET}"
168
+ fi
169
+ fi
170
+
171
+ # ── Right-aligned segments: effort + model ───────────────────────────────────
172
+ SEG_EFFORT=""
173
+ if [ "${AI_TOOLKIT_STATUSLINE_NO_EFFORT:-0}" != "1" ] && [ -n "$EFFORT" ]; then
174
+ case "$EFFORT" in
175
+ xhigh|high) E_COLOR="$C_BOLD_YELLOW" ;;
176
+ medium) E_COLOR="$C_YELLOW" ;;
177
+ *) E_COLOR="$C_DIM" ;;
178
+ esac
179
+ SEG_EFFORT="${C_DIM}effort:${C_RESET}${E_COLOR}${EFFORT}${C_RESET}"
180
+ fi
181
+
182
+ SEG_MODEL=""
183
+ if [ -n "$MODEL_NAME" ]; then
184
+ SEG_MODEL="${C_MAGENTA}${MODEL_NAME}${C_RESET}"
185
+ fi
186
+
187
+ # ── Render (left-aligned, single line) ───────────────────────────────────────
188
+ # Right-align was attempted earlier but Claude Code reserves variable-width
189
+ # space on the right of the rendered statusline for its own UI overlay,
190
+ # truncating any content right-padded near COLUMNS. Left-align with effort
191
+ # and model as trailing segments avoids the truncation.
192
+ SEG_TRAILER=""
193
+ [ -n "$SEG_EFFORT" ] && SEG_TRAILER+=" $SEG_EFFORT"
194
+ [ -n "$SEG_MODEL" ] && SEG_TRAILER+=" $SEG_MODEL"
195
+
196
+ printf "%b%b%b%b%b\n" \
197
+ "$SEG_PROMPT" \
198
+ "${SEG_GIT:-}" \
199
+ "${SEG_CTX:-}" \
200
+ "${SEG_TOKENS:-}" \
201
+ "${SEG_TRAILER}"
package/app/hooks.json CHANGED
@@ -234,5 +234,10 @@
234
234
  ]
235
235
  }
236
236
  ]
237
+ },
238
+ "statusLine": {
239
+ "_source": "ai-toolkit",
240
+ "type": "command",
241
+ "command": "bash \"$HOME/.softspark/ai-toolkit/hooks/ai-toolkit-statusline.sh\""
237
242
  }
238
243
  }
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  name: brand-voice
3
- description: "Loaded when writing documentation, content, README, or user-facing text. Prevents generic LLM rhetoric and enforces direct, technical voice."
3
+ description: "Loaded when writing documentation, content, README, or user-facing text, AND when an output-mode is set for conversational responses. Prevents generic LLM rhetoric, enforces direct technical voice, and supplies optional concise/strict response modes."
4
4
  effort: medium
5
- user-invocable: false
5
+ user-invocable: true
6
6
  allowed-tools: Read
7
7
  ---
8
8
 
@@ -10,6 +10,8 @@ allowed-tools: Read
10
10
 
11
11
  Auto-loaded when writing documentation, content, or user-facing text. Enforces consistent, direct voice and eliminates LLM rhetoric.
12
12
 
13
+ Also loaded when a project sets `output-mode: concise` or `output-mode: strict` in `CLAUDE.md`, to govern conversational response length and structure (see [Output Modes](#output-modes)).
14
+
13
15
  ## Anti-Trope List (Banned Phrases)
14
16
 
15
17
  ### Opening Tropes (Never Start With)
@@ -119,6 +121,40 @@ install takes under 30 seconds on a local disk.
119
121
  - **CRITICAL**: one idea per sentence. If you write "and" linking two distinct ideas, split the sentence
120
122
  - **MANDATORY**: technical claims include a concrete number, name, or example — never assert quality without evidence
121
123
 
124
+ ## Output Modes
125
+
126
+ Three modes govern conversational response length. Default applies always; `concise` and `strict` activate per-project or per-session.
127
+
128
+ | Mode | Token target vs default | Used when |
129
+ |------|-------------------------|-----------|
130
+ | `default` | 100% (no extra constraints) | No `output-mode` configured |
131
+ | `concise` | ≤60% | Daily work, short Q&A, code edits, short reviews |
132
+ | `strict` | ≤40% | Long sessions, expensive models, batch operations, code-only tasks |
133
+
134
+ Mode rules live in this skill's `modes/` directory. Read the file matching the active mode:
135
+
136
+ - `modes/concise.md` — bullet-first, no preamble, max 3-sentence prose blocks
137
+ - `modes/strict.md` — telegraphic, no prose blocks, only lists/tables/code
138
+
139
+ ### Activation
140
+
141
+ 1. **Project-level (preferred):** add `output-mode: concise` to project `CLAUDE.md` frontmatter or `.claude/settings.json` under `aiToolkit.outputMode`
142
+ 2. **Session-level:** user types `/brand-voice concise` or `/brand-voice strict` to switch for the current session
143
+ 3. **Reset:** `/brand-voice default` or remove the project setting
144
+
145
+ ### What modes do NOT change
146
+
147
+ - Code blocks (always full, never truncated)
148
+ - File paths, line numbers, error messages (always exact)
149
+ - Lists of items the user must see (file lists, test failures, security findings)
150
+ - Plan documents and ADRs (always full structure)
151
+
152
+ Modes change *prose*, not *data*. If you cut a fact to fit a length budget, you have failed the mode, not honored it.
153
+
154
+ ### Measurement
155
+
156
+ Run `python3 app/skills/brand-voice/scripts/measure.py --fixtures tests/fixtures/output-modes/` to compare baseline vs mode tokens on the fixture set. Report shows per-fixture deltas and an aggregate ratio.
157
+
122
158
  ## When NOT to Load
123
159
 
124
160
  - For code or technical specs with no user-facing prose — the voice rules do not apply