Skip to content
Open
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
15 changes: 15 additions & 0 deletions .agents/skills/gstack-autoplan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ _PROACTIVE=$(~/.codex/skills/gstack/bin/gstack-config get proactive 2>/dev/null
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
source <(~/.codex/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.codex/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
Expand Down Expand Up @@ -127,6 +130,18 @@ AI-assisted coding makes the marginal cost of completeness near-zero. When you p
- BAD: "Let's defer test coverage to a follow-up PR." (Tests are the cheapest lake to boil.)
- BAD: Quoting only human-team effort: "This would take 2 weeks." (Say: "2 weeks human / ~1 hour CC.")

## Repo Ownership Mode — See Something, Say Something

`REPO_MODE` from the preamble tells you who owns issues in this repo:

- **`solo`** — One person does 80%+ of the work. They own everything. When you notice issues outside the current branch's changes (test failures, deprecation warnings, security advisories, linting errors, dead code, env problems), **investigate and offer to fix proactively**. The solo dev is the only person who will fix it. Default to action.
- **`collaborative`** — Multiple active contributors. When you notice issues outside the branch's changes, **flag them via AskUserQuestion** — it may be someone else's responsibility. Default to asking, not fixing.
- **`unknown`** — Treat as collaborative (safer default — ask before fixing).

**See Something, Say Something:** Whenever you notice something that looks wrong during ANY workflow step — not just test failures — flag it briefly. One sentence: what you noticed and its impact. In solo mode, follow up with "Want me to fix it?" In collaborative mode, just flag it and move on.

Never let a noticed issue silently pass. The whole point is proactive communication.

## Search Before Building

Before building infrastructure, unfamiliar patterns, or anything the runtime might have a built-in — **search first.** Read `~/.codex/skills/gstack/ETHOS.md` for the full philosophy.
Expand Down
22 changes: 1 addition & 21 deletions .agents/skills/gstack/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,27 +18,7 @@ description: |
- Debugging errors → suggest /investigate
- Testing the app → suggest /qa
- Code review before merge → suggest /review
- Visual design audit → suggest /design-review
- Ready to deploy / create PR → suggest /ship
- Post-ship doc updates → suggest /document-release
- Weekly retrospective → suggest /retro
- Wanting a second opinion or adversarial code review → suggest /codex
- Working with production or live systems → suggest /careful
- Want to scope edits to one module/directory → suggest /freeze
- Maximum safety mode (destructive warnings + edit restrictions) → suggest /guard
- Removing edit restrictions → suggest /unfreeze
- Upgrading gstack to latest version → suggest /gstack-upgrade

If the user pushes back on skill suggestions ("stop suggesting things",
"I don't need suggestions", "too aggressive"):
1. Stop suggesting for the rest of this session
2. Run: gstack-config set proactive false
3. Say: "Got it — I'll stop suggesting skills. Just tell me to be proactive
again if you change your mind."

If the user says "be proactive again" or "turn on suggestions":
1. Run: gstack-config set proactive true
2. Say: "Proactive suggestions are back on."
- Visual design audit →...
---
<!-- AUTO-GENERATED from SKILL.md.tmpl — do not edit directly -->
<!-- Regenerate: bun run gen:skill-docs -->
Expand Down
15 changes: 15 additions & 0 deletions autoplan/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ _PROACTIVE=$(~/.claude/skills/gstack/bin/gstack-config get proactive 2>/dev/null
_BRANCH=$(git branch --show-current 2>/dev/null || echo "unknown")
echo "BRANCH: $_BRANCH"
echo "PROACTIVE: $_PROACTIVE"
source <(~/.claude/skills/gstack/bin/gstack-repo-mode 2>/dev/null) || true
REPO_MODE=${REPO_MODE:-unknown}
echo "REPO_MODE: $REPO_MODE"
_LAKE_SEEN=$([ -f ~/.gstack/.completeness-intro-seen ] && echo "yes" || echo "no")
echo "LAKE_INTRO: $_LAKE_SEEN"
_TEL=$(~/.claude/skills/gstack/bin/gstack-config get telemetry 2>/dev/null || true)
Expand Down Expand Up @@ -138,6 +141,18 @@ AI-assisted coding makes the marginal cost of completeness near-zero. When you p
- BAD: "Let's defer test coverage to a follow-up PR." (Tests are the cheapest lake to boil.)
- BAD: Quoting only human-team effort: "This would take 2 weeks." (Say: "2 weeks human / ~1 hour CC.")

## Repo Ownership Mode — See Something, Say Something

`REPO_MODE` from the preamble tells you who owns issues in this repo:

- **`solo`** — One person does 80%+ of the work. They own everything. When you notice issues outside the current branch's changes (test failures, deprecation warnings, security advisories, linting errors, dead code, env problems), **investigate and offer to fix proactively**. The solo dev is the only person who will fix it. Default to action.
- **`collaborative`** — Multiple active contributors. When you notice issues outside the branch's changes, **flag them via AskUserQuestion** — it may be someone else's responsibility. Default to asking, not fixing.
- **`unknown`** — Treat as collaborative (safer default — ask before fixing).

**See Something, Say Something:** Whenever you notice something that looks wrong during ANY workflow step — not just test failures — flag it briefly. One sentence: what you noticed and its impact. In solo mode, follow up with "Want me to fix it?" In collaborative mode, just flag it and move on.

Never let a noticed issue silently pass. The whole point is proactive communication.

## Search Before Building

Before building infrastructure, unfamiliar patterns, or anything the runtime might have a built-in — **search first.** Read `~/.claude/skills/gstack/ETHOS.md` for the full philosophy.
Expand Down
14 changes: 14 additions & 0 deletions scripts/gen-skill-docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2250,6 +2250,7 @@ function transformFrontmatter(content: string, host: Host): string {
if (descLines.length > 0) {
description = descLines.join('\n').trim();
}
description = truncateCodexDescription(description);

// Re-emit Codex frontmatter (name + description only)
const indentedDesc = description.split('\n').map(l => ` ${l}`).join('\n');
Expand Down Expand Up @@ -2291,6 +2292,19 @@ function extractHookSafetyProse(tmplContent: string): string | null {
// ─── Template Processing ────────────────────────────────────

const GENERATED_HEADER = `<!-- AUTO-GENERATED from {{SOURCE}} — do not edit directly -->\n<!-- Regenerate: bun run gen:skill-docs -->\n`;
const CODEX_DESCRIPTION_MAX_LENGTH = 1024;

function truncateCodexDescription(description: string, maxLength = CODEX_DESCRIPTION_MAX_LENGTH): string {
if (description.length <= maxLength) return description;

const truncated = description.slice(0, Math.max(0, maxLength - 3));
const safeBoundary = Math.max(
truncated.lastIndexOf('\n'),
truncated.lastIndexOf(' '),
);
const base = (safeBoundary > 0 ? truncated.slice(0, safeBoundary) : truncated).trimEnd();
return `${base}...`;
}

function processTemplate(tmplPath: string, host: Host = 'claude'): { outputPath: string; content: string } {
const tmplContent = fs.readFileSync(tmplPath, 'utf-8');
Expand Down
4 changes: 2 additions & 2 deletions setup
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,9 @@ if [ "$INSTALL_CODEX" -eq 1 ]; then
CODEX_GSTACK="$CODEX_SKILLS/gstack"
mkdir -p "$CODEX_SKILLS"

# Symlink gstack source for runtime assets (bin/, browse/dist/)
# Symlink the generated Codex root skill; runtime assets are provided via sidecars.
if [ -L "$CODEX_GSTACK" ] || [ ! -e "$CODEX_GSTACK" ]; then
ln -snf "$GSTACK_DIR" "$CODEX_GSTACK"
ln -snf "$GSTACK_DIR/.agents/skills/gstack" "$CODEX_GSTACK"
fi
# Install generated Codex-format skills (not Claude source dirs)
link_codex_skill_dirs "$GSTACK_DIR" "$CODEX_SKILLS"
Expand Down
42 changes: 42 additions & 0 deletions test/gen-skill-docs.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,30 @@ import * as path from 'path';

const ROOT = path.resolve(import.meta.dir, '..');

function extractFrontmatterDescription(content: string): string {
const fmEnd = content.indexOf('\n---', 4);
expect(fmEnd).toBeGreaterThan(0);
const frontmatter = content.slice(4, fmEnd);
const lines = frontmatter.split('\n');
const descStart = lines.findIndex(line => line.trim() === 'description: |');

if (descStart === -1) {
const inline = lines.find(line => line.startsWith('description: '));
return inline ? inline.replace(/^description:\s*/, '').trim() : '';
}

const descLines: string[] = [];
for (const line of lines.slice(descStart + 1)) {
if (line === '' || line.startsWith(' ')) {
descLines.push(line.startsWith(' ') ? line.slice(2) : '');
continue;
}
break;
}

return descLines.join('\n').trim();
}

// Dynamic template discovery — matches the generator's findTemplates() behavior.
// New skills automatically get test coverage without updating a static list.
const ALL_SKILLS = (() => {
Expand Down Expand Up @@ -806,6 +830,14 @@ describe('Codex generation (--host codex)', () => {
expect(frontmatter).toContain('YC Office Hours');
});

test('Codex descriptions stay within host frontmatter limit', () => {
for (const skill of CODEX_SKILLS) {
const content = fs.readFileSync(path.join(AGENTS_DIR, skill.codexName, 'SKILL.md'), 'utf-8');
const description = extractFrontmatterDescription(content);
expect(description.length).toBeLessThanOrEqual(1024);
}
});

test('hook skills have safety prose and no hooks: in frontmatter', () => {
const HOOK_SKILLS = ['gstack-careful', 'gstack-freeze', 'gstack-guard'];
for (const skillName of HOOK_SKILLS) {
Expand Down Expand Up @@ -960,6 +992,16 @@ describe('setup script validation', () => {
expect(codexSection).not.toContain('link_claude_skill_dirs');
});

test('Codex root install points at generated gstack skill, not repo root', () => {
const codexSection = setupContent.slice(
setupContent.indexOf('# 5. Install for Codex'),
setupContent.indexOf('# 6. Create')
);
expect(codexSection).toContain('CODEX_GSTACK="$CODEX_SKILLS/gstack"');
expect(codexSection).toContain('ln -snf "$GSTACK_DIR/.agents/skills/gstack" "$CODEX_GSTACK"');
expect(codexSection).not.toContain('ln -snf "$GSTACK_DIR" "$CODEX_GSTACK"');
});

test('link_codex_skill_dirs reads from .agents/skills/', () => {
// The Codex link function must reference .agents/skills for generated Codex skills
const fnStart = setupContent.indexOf('link_codex_skill_dirs()');
Expand Down