Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion skills/gitguardex/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ Use when repo safety may be broken.
Bootstrap: `gx setup`
Ops: `gx branch start "<task>" "<agent>"`, `gx locks claim --branch "<agent-branch>" <file...>`, `gx branch finish --branch "<agent-branch>" --base <base> --via-pr --wait-for-merge --cleanup`, `gx finish --all`, `gx cleanup`

When inspecting or verifying, prefer `rtk` compact wrappers if available (`rtk git status`, `rtk grep`, `rtk test <cmd>`). Do not wrap commands whose stdout is parsed by scripts.
When inspecting or verifying, prefer `rtk` compact wrappers if available (`rtk git status`, `rtk grep`, `rtk test <cmd>`, and noisy gx reads like `rtk gx status` / `rtk gx doctor`). Do not wrap commands whose stdout is parsed by scripts (`--json`, `--porcelain`, exact stdout contracts) or shell-ready output (`gx prompt --exec`).

To shrink gx's own large narrative output (e.g. `gx prompt`, `gx prompt --snippet`) before it lands in your context, set `GUARDEX_COMPRESS_CMD="<stdin->stdout filter>"`; gx routes that output through the filter (terse/non-TTY mode, fail-open, JSON skipped). Unset = byte-for-byte unchanged.
13 changes: 11 additions & 2 deletions src/cli/commands/prompt.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,16 @@ function printAgentsSnippet() {
}

function copyPrompt() {
process.stdout.write(AI_SETUP_PROMPT);
// AI_SETUP_PROMPT is the large narrative checklist an agent reads each
// session, so route it through the optional compressor (GUARDEX_COMPRESS_CMD)
// exactly like the main `gx prompt` path and `printAgentsSnippet`.
process.stdout.write(compressBlock(AI_SETUP_PROMPT));
process.exitCode = 0;
}

function copyCommands() {
// AI_SETUP_COMMANDS is shell-ready output (runnable commands), so it is never
// compressed — a compressor would corrupt the commands an agent pastes.
process.stdout.write(AI_SETUP_COMMANDS);
process.exitCode = 0;
}
Expand Down Expand Up @@ -83,7 +88,11 @@ function prompt(rawArgs) {
process.exitCode = 0;
return;
}
process.stdout.write(renderAiSetupPrompt({ exec: variant === 'exec', parts: selectedParts }));
const rendered = renderAiSetupPrompt({ exec: variant === 'exec', parts: selectedParts });
// The default/prompt variant is the large narrative checklist; route it
// through the optional compressor. The --exec variant is shell-ready output
// (runnable commands) and must never be compressed.
process.stdout.write(variant === 'exec' ? rendered : compressBlock(rendered));
process.exitCode = 0;
}

Expand Down
4 changes: 2 additions & 2 deletions templates/AGENTS.multiagent-safety.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ Persist unresolved questions or blockers into `openspec/plan/<plan-slug>/open-qu
### Optional companion tooling (use if installed)

- **fff MCP** (file search): prefer for all file search; fall back to `rtk grep`/`rtk find` or `rg`.
- **rtk** (shell compression): wrap noisy discovery (`rtk ls`/`grep`/`find`/`read`), git/gh (`rtk git status`/`gh pr list`), and verification (`rtk tsc`/`lint`/`test`). Do **not** wrap machine-readable commands (`--porcelain`, `--json`, exact stdout contracts).
- **headroom** (context compression): when available, run large `gx` output, long logs, and big file/diff dumps through `headroom_compress` before reasoning over them (reversible — `headroom_retrieve` restores). Or set `GUARDEX_COMPRESS_CMD="<filter>"` so gx routes its own large narrative output through your compressor. Keep PR URLs, branch names, and file paths visible; never compress `--json`/`--porcelain` or values you act on verbatim.
- **rtk** (shell compression): wrap noisy discovery (`rtk ls`/`grep`/`find`/`read`), git/gh (`rtk git status`/`gh pr list`), verification (`rtk tsc`/`lint`/`test`), and noisy gx reads (`rtk gx status`/`rtk gx doctor`). Do **not** wrap machine-readable commands (`--porcelain`, `--json`, exact stdout contracts) or shell-ready output (`gx prompt --exec`).
- **headroom** (context compression): when available, run large `gx` output, long logs, and big file/diff dumps through `headroom_compress` before reasoning over them (reversible — `headroom_retrieve` restores). Or set `GUARDEX_COMPRESS_CMD="<filter>"` so gx routes its own large narrative output — `gx prompt`, `gx prompt --snippet` — through your compressor (terse/non-TTY only, fail-open, JSON skipped; `--exec` stays raw). Keep PR URLs, branch names, and file paths visible; never compress `--json`/`--porcelain` or values you act on verbatim.
- **OpenSpec**: keep `openspec/changes/<slug>/tasks.md` current during work, not batched. Validate with `openspec validate --specs` before archive.

### Token / context budget
Expand Down
4 changes: 3 additions & 1 deletion templates/codex/skills/gitguardex/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,6 @@ Use when repo safety may be broken.
Bootstrap: `gx setup`
Ops: `gx branch start "<task>" "<agent>"`, `gx locks claim --branch "<agent-branch>" <file...>`, `gx branch finish --branch "<agent-branch>" --base <base> --via-pr --wait-for-merge --cleanup`, `gx finish --all`, `gx cleanup`

When inspecting or verifying, prefer `rtk` compact wrappers if available (`rtk git status`, `rtk grep`, `rtk test <cmd>`). Do not wrap commands whose stdout is parsed by scripts.
When inspecting or verifying, prefer `rtk` compact wrappers if available (`rtk git status`, `rtk grep`, `rtk test <cmd>`, and noisy gx reads like `rtk gx status` / `rtk gx doctor`). Do not wrap commands whose stdout is parsed by scripts (`--json`, `--porcelain`, exact stdout contracts) or shell-ready output (`gx prompt --exec`).

To shrink gx's own large narrative output (e.g. `gx prompt`, `gx prompt --snippet`) before it lands in your context, set `GUARDEX_COMPRESS_CMD="<stdin->stdout filter>"`; gx routes that output through the filter (terse/non-TTY mode, fail-open, JSON skipped). Unset = byte-for-byte unchanged.
27 changes: 27 additions & 0 deletions test/prompt.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,33 @@ test('prompt --snippet is unchanged when GUARDEX_COMPRESS_CMD points at a missin
assert.match(result.stdout, /<!-- multiagent-safety:START -->/);
});

test('prompt (default checklist) routes through GUARDEX_COMPRESS_CMD when set', () => {
const repoDir = initRepo();
const plain = runNode(['prompt'], repoDir);
assert.equal(plain.status, 0, plain.stderr || plain.stdout);
assert.match(plain.stdout, /GitGuardex \(gx\) setup checklist/);

const compressed = runNodeWithEnv(['prompt'], repoDir, {
GUARDEX_COMPRESS_CMD: 'tr a-z A-Z',
});
assert.equal(compressed.status, 0, compressed.stderr || compressed.stdout);
// `tr a-z A-Z` uppercases the whole block, proving it was piped through.
assert.match(compressed.stdout, /GITGUARDEX \(GX\) SETUP CHECKLIST/);
assert.doesNotMatch(compressed.stdout, /GitGuardex \(gx\) setup checklist/);
});

test('prompt --exec is never compressed (shell-ready output stays runnable)', () => {
const repoDir = initRepo();
// Even with a compressor configured, --exec output must pass through raw so
// the commands an agent pastes are not mangled.
const result = runNodeWithEnv(['prompt', '--exec'], repoDir, {
GUARDEX_COMPRESS_CMD: 'tr a-z A-Z',
});
assert.equal(result.status, 0, result.stderr || result.stdout);
assert.match(result.stdout, /^npm i -g @imdeadpool\/guardex/m);
assert.doesNotMatch(result.stdout, /NPM I -G @IMDEADPOOL/);
});


test('deprecated copy-prompt alias still works and warns', () => {
const repoDir = initRepo();
Expand Down
Loading