feat: /gsd-settings-integrations — configure third-party search and review integrations (closes #2529) (#2604)
* feat(#2529): /gsd-settings-integrations — third-party integrations command Adds /gsd-settings-integrations for configuring API keys, code-review CLI routing, and agent-skill injection. Distinct from /gsd-settings (workflow toggles) because these are connectivity, not pipeline shape. Three sections: - Search Integrations: brave_search / firecrawl / exa_search API keys, plus search_gitignored toggle. - Code Review CLI Routing: review.models.{claude,codex,gemini,opencode} shell-command strings. - Agent Skills Injection: agent_skills.<agent-type> free-text input, validated against [a-zA-Z0-9_-]+. Security: - New secrets.cjs module with ****<last-4> masking convention. - cmdConfigSet now masks value/previousValue in CLI output for secret keys. - Plaintext is written only to .planning/config.json; never echoed to stdout/stderr, never written to audit/log files by this flow. - Slug validators reject path separators, whitespace, shell metacharacters. Tests (tests/settings-integrations.test.cjs — 25 cases): - Artifact presence / frontmatter. - Field round-trips via gsd-tools config-set for all four search keys, review.models.<cli>, agent_skills.<agent-type>. - Config-merge safety: unrelated keys preserved across writes. - Masking: config-set output never contains plaintext sentinel. - Logging containment: plaintext secret sentinel appears only in config.json under .planning/, nowhere else on disk. - Negative: path-traversal, shell-metachar, and empty-slug rejected. - /gsd:settings workflow mentions /gsd:settings-integrations. Docs: - docs/COMMANDS.md: new command entry with security note. - docs/CONFIGURATION.md: integration settings section (keys, routing, skills injection) with masking documentation. - docs/CLI-TOOLS.md: reviewer CLI routing and secret-handling sections. - docs/INVENTORY.md + INVENTORY-MANIFEST.json regenerated. Closes #2529 * fix(#2529): mask secrets in config-get; address CodeRabbit review cmdConfigGet was emitting plaintext for brave_search/firecrawl/exa_search. Apply the same isSecretKey/maskSecret treatment used by config-set so the CLI surface never echoes raw API keys; plaintext still lives only in config.json on disk. Also addresses CodeRabbit review items in the same PR area: - #3127146188: config-get plaintext leak (root fix above) - #3127146211: rename test sentinels to concat-built markers so secret scanners stop flagging the test file. Behavior preserved. - #3127146207: add explicit 'text' language to fenced code blocks (MD040). - nitpick: unify masked-value wording in read_current legend ('****<last-4>' instead of '**** already set'). - nitpick: extend round-trip test to cover search_gitignored toggle. New regression test 'config-get masks secrets and never echoes plaintext' verifies the fix for all three secret keys. * docs(#2529): bump INVENTORY counts post-rebase (commands 84→85, workflows 82→83) * fix(test): bump CLI Modules count 27→28 after rebase onto main (CI #24811455435) PR #2604 was rebased onto main before #2605 (drift.cjs) merged. The pull_request CI runs against the merge ref (refs/pull/2604/merge), which now contains 28 .cjs files in get-shit-done/bin/lib/, but docs/INVENTORY.md headline still said "(27 shipped)". inventory-counts.test.cjs failed with: AssertionError: docs/INVENTORY.md "CLI Modules (27 shipped)" disagrees with get-shit-done/bin/lib/ file count (28) Rebased branch onto current origin/main (picks up drift.cjs row, which was already added by #2605) and bumped the headline to 28. Full suite: 5200/5200 pass.
This commit is contained in:
@@ -475,6 +475,25 @@ User-facing entry point: `/gsd-graphify` (see [Command Reference](COMMANDS.md#gs
|
||||
|
||||
---
|
||||
|
||||
## Reviewer CLI Routing
|
||||
|
||||
`review.models.<cli>` maps a reviewer flavor to a shell command invoked by the code-review workflow. Set via [`/gsd-settings-integrations`](COMMANDS.md#gsd-settings-integrations) or directly:
|
||||
|
||||
```bash
|
||||
gsd-sdk query config-set review.models.codex "codex exec --model gpt-5"
|
||||
gsd-sdk query config-set review.models.gemini "gemini -m gemini-2.5-pro"
|
||||
gsd-sdk query config-set review.models.opencode "opencode run --model claude-sonnet-4"
|
||||
gsd-sdk query config-set review.models.claude "" # clear — fall back to session model
|
||||
```
|
||||
|
||||
Slugs are validated against `[a-zA-Z0-9_-]+`; empty or path-containing slugs are rejected. See [`docs/CONFIGURATION.md`](CONFIGURATION.md#code-review-cli-routing) for the full field reference.
|
||||
|
||||
## Secret Handling
|
||||
|
||||
API keys configured via `/gsd-settings-integrations` (`brave_search`, `firecrawl`, `exa_search`) are written plaintext to `.planning/config.json` but are masked (`****<last-4>`) in every `config-set` / `config-get` output, confirmation table, and interactive prompt. See `get-shit-done/bin/lib/secrets.cjs` for the masking implementation. The `config.json` file itself is the security boundary — protect it with filesystem permissions and keep it out of git (`.planning/` is gitignored by default).
|
||||
|
||||
---
|
||||
|
||||
## See also
|
||||
|
||||
- [sdk/src/query/QUERY-HANDLERS.md](../sdk/src/query/QUERY-HANDLERS.md) — registry matrix, routing, golden parity, intentional CJS differences
|
||||
|
||||
@@ -1075,6 +1075,35 @@ Current values are pre-selected; an empty input keeps the existing value. Numeri
|
||||
|
||||
See [CONFIGURATION.md](CONFIGURATION.md) for the full schema and defaults.
|
||||
|
||||
### `/gsd-settings-integrations`
|
||||
|
||||
Interactive configuration of third-party integrations and cross-tool routing.
|
||||
Distinct from `/gsd-settings` (workflow toggles) — this command handles
|
||||
connectivity: API keys, reviewer CLI routing, and agent-skill injection.
|
||||
|
||||
Covers:
|
||||
|
||||
- **Search integrations:** `brave_search`, `firecrawl`, `exa_search` API keys,
|
||||
and the `search_gitignored` toggle.
|
||||
- **Code-review CLI routing:** `review.models.{claude,codex,gemini,opencode}`
|
||||
— a shell command per reviewer flavor.
|
||||
- **Agent-skill injection:** `agent_skills.<agent-type>` — skill names
|
||||
injected into an agent's spawn frontmatter. Agent-type slugs are validated
|
||||
against `[a-zA-Z0-9_-]+` so path separators and shell metacharacters are
|
||||
rejected.
|
||||
|
||||
API keys are stored plaintext in `.planning/config.json` but displayed masked
|
||||
(`****<last-4>`) in every interactive output, confirmation table, and
|
||||
`config-set` stdout/stderr line. Plaintext is never echoed, never logged,
|
||||
and never written to any file outside `config.json` by this workflow.
|
||||
|
||||
```bash
|
||||
/gsd-settings-integrations # Interactive config (three sections)
|
||||
```
|
||||
|
||||
See [`docs/CONFIGURATION.md`](CONFIGURATION.md) for the per-field reference and
|
||||
[`docs/CLI-TOOLS.md`](CLI-TOOLS.md) for the reviewer-CLI routing contract.
|
||||
|
||||
### `/gsd-set-profile`
|
||||
|
||||
Quick profile switch.
|
||||
|
||||
@@ -129,6 +129,41 @@ GSD stores project settings in `.planning/config.json`. Created during `/gsd-new
|
||||
|
||||
---
|
||||
|
||||
## Integration Settings
|
||||
|
||||
Configured interactively via [`/gsd-settings-integrations`](COMMANDS.md#gsd-settings-integrations). These are *connectivity* settings — API keys and cross-tool routing — and are intentionally kept separate from `/gsd-settings` (workflow toggles).
|
||||
|
||||
### Search API keys
|
||||
|
||||
API key fields accept a string value (the key itself). They can also be set to the sentinels `true`/`false`/`null` to override auto-detection from env vars / `~/.gsd/*_api_key` files (legacy behavior, see rows above).
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `brave_search` | string \| boolean \| null | `null` | Brave Search API key used for web research. Displayed as `****<last-4>` in all UI / `config-set` output; never echoed plaintext |
|
||||
| `firecrawl` | string \| boolean \| null | `null` | Firecrawl API key for deep-crawl scraping. Masked in display |
|
||||
| `exa_search` | string \| boolean \| null | `null` | Exa Search API key for semantic search. Masked in display |
|
||||
|
||||
**Masking convention (`get-shit-done/bin/lib/secrets.cjs`):** keys 8+ characters render as `****<last-4>`; shorter keys render as `****`; `null`/empty renders as `(unset)`. Plaintext is written as-is to `.planning/config.json` — that file is the security boundary — but the CLI, confirmation tables, logs, and `AskUserQuestion` descriptions never display the plaintext. This applies to the `config-set` command output itself: `config-set brave_search <key>` returns a JSON payload with the value masked.
|
||||
|
||||
### Code-review CLI routing
|
||||
|
||||
`review.models.<cli>` maps a reviewer flavor to a shell command. The code-review workflow shells out using this command when a matching flavor is requested.
|
||||
|
||||
| Setting | Type | Default | Description |
|
||||
|---------|------|---------|-------------|
|
||||
| `review.models.claude` | string | (session model) | Command for Claude-flavored review. Defaults to the session model when unset |
|
||||
| `review.models.codex` | string | `null` | Command for Codex review, e.g. `"codex exec --model gpt-5"` |
|
||||
| `review.models.gemini` | string | `null` | Command for Gemini review, e.g. `"gemini -m gemini-2.5-pro"` |
|
||||
| `review.models.opencode` | string | `null` | Command for OpenCode review, e.g. `"opencode run --model claude-sonnet-4"` |
|
||||
|
||||
The `<cli>` slug is validated against `[a-zA-Z0-9_-]+`. Empty or path-containing slugs are rejected by `config-set`.
|
||||
|
||||
### Agent-skill injection (dynamic)
|
||||
|
||||
`agent_skills.<agent-type>` extends the `agent_skills` map documented below. Slug is validated against `[a-zA-Z0-9_-]+` — no path separators, no whitespace, no shell metacharacters. Configured interactively via `/gsd-settings-integrations`.
|
||||
|
||||
---
|
||||
|
||||
## Workflow Toggles
|
||||
|
||||
All workflow toggles follow the **absent = enabled** pattern. If a key is missing from config, it defaults to `true`.
|
||||
|
||||
@@ -104,6 +104,7 @@
|
||||
"/gsd-set-profile",
|
||||
"/gsd-settings",
|
||||
"/gsd-settings-advanced",
|
||||
"/gsd-settings-integrations",
|
||||
"/gsd-ship",
|
||||
"/gsd-sketch",
|
||||
"/gsd-sketch-wrap-up",
|
||||
@@ -187,6 +188,7 @@
|
||||
"secure-phase.md",
|
||||
"session-report.md",
|
||||
"settings-advanced.md",
|
||||
"settings-integrations.md",
|
||||
"settings.md",
|
||||
"ship.md",
|
||||
"sketch-wrap-up.md",
|
||||
@@ -280,6 +282,7 @@
|
||||
"profile-pipeline.cjs",
|
||||
"roadmap.cjs",
|
||||
"schema-detect.cjs",
|
||||
"secrets.cjs",
|
||||
"security.cjs",
|
||||
"state.cjs",
|
||||
"template.cjs",
|
||||
|
||||
@@ -54,7 +54,7 @@ Full roster at `agents/gsd-*.md`. The "Primary doc" column flags whether [`docs/
|
||||
|
||||
---
|
||||
|
||||
## Commands (84 shipped)
|
||||
## Commands (85 shipped)
|
||||
|
||||
Full roster at `commands/gsd/*.md`. The groupings below mirror `docs/COMMANDS.md` section order; each row carries the command name, a one-line role derived from the command's frontmatter `description:`, and a link to the source file. `tests/command-count-sync.test.cjs` locks the count against the filesystem.
|
||||
|
||||
@@ -164,6 +164,7 @@ Full roster at `commands/gsd/*.md`. The groupings below mirror `docs/COMMANDS.md
|
||||
| `/gsd-profile-user` | Generate developer behavioral profile and Claude-discoverable artifacts. | [commands/gsd/profile-user.md](../commands/gsd/profile-user.md) |
|
||||
| `/gsd-settings` | Configure GSD workflow toggles and model profile. | [commands/gsd/settings.md](../commands/gsd/settings.md) |
|
||||
| `/gsd-settings-advanced` | Power-user configuration — plan bounce, timeouts, branch templates, cross-AI execution, runtime knobs. | [commands/gsd/settings-advanced.md](../commands/gsd/settings-advanced.md) |
|
||||
| `/gsd-settings-integrations` | Configure third-party API keys, code-review CLI routing, and agent-skill injection. | [commands/gsd/settings-integrations.md](../commands/gsd/settings-integrations.md) |
|
||||
| `/gsd-set-profile` | Switch model profile for GSD agents (quality/balanced/budget/inherit). | [commands/gsd/set-profile.md](../commands/gsd/set-profile.md) |
|
||||
| `/gsd-pr-branch` | Create a clean PR branch by filtering out `.planning/` commits. | [commands/gsd/pr-branch.md](../commands/gsd/pr-branch.md) |
|
||||
| `/gsd-sync-skills` | Sync managed GSD skill directories across runtime roots for multi-runtime users. | [commands/gsd/sync-skills.md](../commands/gsd/sync-skills.md) |
|
||||
@@ -174,7 +175,7 @@ Full roster at `commands/gsd/*.md`. The groupings below mirror `docs/COMMANDS.md
|
||||
|
||||
---
|
||||
|
||||
## Workflows (82 shipped)
|
||||
## Workflows (83 shipped)
|
||||
|
||||
Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators that commands reference internally; most are not read directly by end users. Rows below map each workflow file to its role (derived from the `<purpose>` block) and, where applicable, to the command that invokes it.
|
||||
|
||||
@@ -245,6 +246,7 @@ Full roster at `get-shit-done/workflows/*.md`. Workflows are thin orchestrators
|
||||
| `session-report.md` | Session report — token usage, work summary, outcomes. | `/gsd-session-report` |
|
||||
| `settings.md` | Configure GSD workflow toggles and model profile. | `/gsd-settings`, `/gsd-set-profile` |
|
||||
| `settings-advanced.md` | Configure GSD power-user knobs — plan bounce, timeouts, branch templates, cross-AI execution, runtime knobs. | `/gsd-settings-advanced` |
|
||||
| `settings-integrations.md` | Configure third-party API keys (Brave/Firecrawl/Exa), `review.models.<cli>` CLI routing, and `agent_skills.<agent-type>` injection with masked (`****<last-4>`) display. | `/gsd-settings-integrations` |
|
||||
| `ship.md` | Create PR, run review, and prepare for merge after verification. | `/gsd-ship` |
|
||||
| `sketch.md` | Explore design directions through throwaway HTML mockups with 2-3 variants per sketch. | `/gsd-sketch` |
|
||||
| `sketch-wrap-up.md` | Curate sketch findings and package them as a persistent `sketch-findings-[project]` skill. | `/gsd-sketch-wrap-up` |
|
||||
@@ -356,7 +358,7 @@ The `gsd-planner` agent is decomposed into a core agent plus reference modules t
|
||||
|
||||
---
|
||||
|
||||
## CLI Modules (27 shipped)
|
||||
## CLI Modules (28 shipped)
|
||||
|
||||
Full listing: `get-shit-done/bin/lib/*.cjs`.
|
||||
|
||||
@@ -383,6 +385,7 @@ Full listing: `get-shit-done/bin/lib/*.cjs`.
|
||||
| `profile-pipeline.cjs` | User behavioral profiling data pipeline, session file scanning |
|
||||
| `roadmap.cjs` | ROADMAP.md parsing, phase extraction, plan progress |
|
||||
| `schema-detect.cjs` | Schema-drift detection for ORM patterns (Prisma, Drizzle, etc.) |
|
||||
| `secrets.cjs` | Secret-config masking convention (`****<last-4>`) for integration keys managed by `/gsd-settings-integrations` — keeps plaintext out of `config-set` output |
|
||||
| `security.cjs` | Path traversal prevention, prompt injection detection, safe JSON/shell helpers |
|
||||
| `state.cjs` | STATE.md parsing, updating, progression, metrics |
|
||||
| `template.cjs` | Template selection and filling with variable substitution |
|
||||
|
||||
Reference in New Issue
Block a user