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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ bin/gstack-global-discover
.claude/skills/
.agents/
.factory/
.opencode/
.context/
extension/.auth.json
.gstack-worktrees/
Expand Down
24 changes: 23 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Fork it. Improve it. Make it yours. And if you want to hate on free open source

## Install — 30 seconds

**Requirements:** [Claude Code](https://docs.anthropic.com/en/docs/claude-code), [Git](https://git-scm.com/), [Bun](https://bun.sh/) v1.0+, [Node.js](https://nodejs.org/) (Windows only)
**Requirements:** [Claude Code](https://docs.anthropic.com/en/docs/claude-code) or [OpenCode](https://opencode.ai/), [Git](https://git-scm.com/), [Bun](https://bun.sh/) v1.0+, [Node.js](https://nodejs.org/) (Windows only)

### Step 1: Install on your machine

Expand Down Expand Up @@ -92,6 +92,28 @@ cd ~/gstack && ./setup --host auto

For Codex-compatible hosts, setup now supports both repo-local installs from `.agents/skills/gstack` and user-global installs from `~/.codex/skills/gstack`. All 31 skills work across all supported agents. Hook-based safety skills (careful, freeze, guard) use inline safety advisory prose on non-Claude hosts.

### OpenCode

OpenCode natively reads `SKILL.md` skills from `.opencode/skills/` in a repo or `~/.config/opencode/skills/` globally. gstack generates a native OpenCode skill layout, keeps `AGENTS.md` references correct, and preserves the runtime root at `.opencode/skills/gstack` for shared assets.

Install to one repo:

```bash
git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git .opencode/skills/gstack
cd .opencode/skills/gstack && ./setup --host opencode
```

Install once for your user account:

```bash
git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git ~/gstack
cd ~/gstack && ./setup --host opencode
```

Global installs create the OpenCode runtime root at `~/.config/opencode/skills/gstack` and link each generated skill into `~/.config/opencode/skills/`. Repo-local installs keep everything inside `.opencode/skills/` so teammates get the same setup from git.

If you use project instructions, put gstack routing rules in `AGENTS.md` instead of `CLAUDE.md`.

### Factory Droid

gstack works with [Factory Droid](https://factory.ai). Skills install to `.factory/skills/` and are discovered automatically. Sensitive skills (ship, land-and-deploy, guard) use `disable-model-invocation: true` so Droids don't auto-invoke them.
Expand Down
5 changes: 3 additions & 2 deletions bin/gstack-platform-detect
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,18 @@ set -euo pipefail
# gstack-platform-detect: show which AI coding agents are installed and gstack status
printf "%-16s %-10s %-40s %s\n" "Agent" "Version" "Skill Path" "gstack"
printf "%-16s %-10s %-40s %s\n" "-----" "-------" "----------" "------"
for entry in "claude:claude" "codex:codex" "droid:factory" "kiro-cli:kiro"; do
for entry in "claude:claude" "opencode:opencode" "codex:codex" "droid:factory" "kiro-cli:kiro"; do
bin="${entry%%:*}"; label="${entry##*:}"
if command -v "$bin" >/dev/null 2>&1; then
ver=$("$bin" --version 2>/dev/null | head -1 || echo "unknown")
case "$label" in
claude) spath="$HOME/.claude/skills/gstack" ;;
opencode) spath="$HOME/.config/opencode/skills/gstack" ;;
codex) spath="$HOME/.codex/skills/gstack" ;;
factory) spath="$HOME/.factory/skills/gstack" ;;
kiro) spath="$HOME/.kiro/skills/gstack" ;;
esac
status=$([ -d "$spath" ] && echo "INSTALLED" || echo "NOT INSTALLED")
status=$([ -d "$spath" ] || [ -L "$spath" ] && echo "INSTALLED" || echo "NOT INSTALLED")
printf "%-16s %-10s %-40s %s\n" "$label" "$ver" "$spath" "$status"
fi
done
66 changes: 66 additions & 0 deletions bin/gstack-uninstall
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
# What gets REMOVED:
# ~/.claude/skills/gstack — global Claude skill install (git clone or vendored)
# ~/.claude/skills/{skill} — per-skill symlinks created by setup
# ~/.config/opencode/skills/gstack — global OpenCode runtime root
# ~/.config/opencode/skills/{skill} — OpenCode per-skill links created by setup
# ~/.codex/skills/gstack* — Codex skill install + per-skill symlinks
# ~/.factory/skills/gstack* — Factory Droid skill install + per-skill symlinks
# ~/.kiro/skills/gstack* — Kiro skill install + per-skill symlinks
# ~/.gstack/ — global state (config, analytics, sessions, projects,
# repos, installation-id, browse error logs)
# .claude/skills/gstack* — project-local skill install (--local installs)
# .opencode/skills/gstack* — project-local OpenCode install (--local installs)
# .gstack/ — per-project browse state (in current git repo)
# .gstack-worktrees/ — per-project test worktrees (in current git repo)
# .agents/skills/gstack* — Codex/Gemini/Cursor sidecar (in current git repo)
Expand All @@ -39,6 +42,16 @@ fi
GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}"
STATE_DIR="${GSTACK_STATE_DIR:-$HOME/.gstack}"
_GIT_ROOT="$(git rev-parse --show-toplevel 2>/dev/null || true)"
_LOCAL_INSTALL_ROOT=""
case "$GSTACK_DIR" in
*/.claude/skills/gstack) _LOCAL_INSTALL_ROOT="${GSTACK_DIR%/.claude/skills/gstack}" ;;
*/.opencode/skills/gstack) _LOCAL_INSTALL_ROOT="${GSTACK_DIR%/.opencode/skills/gstack}" ;;
*/.agents/skills/gstack) _LOCAL_INSTALL_ROOT="${GSTACK_DIR%/.agents/skills/gstack}" ;;
*/.factory/skills/gstack) _LOCAL_INSTALL_ROOT="${GSTACK_DIR%/.factory/skills/gstack}" ;;
esac
if [ -n "$_LOCAL_INSTALL_ROOT" ] && { [ -d "$_LOCAL_INSTALL_ROOT/.git" ] || [ -f "$_LOCAL_INSTALL_ROOT/.git" ]; }; then
_GIT_ROOT="$_LOCAL_INSTALL_ROOT"
fi

# ─── Parse flags ─────────────────────────────────────────────
FORCE=0
Expand All @@ -63,13 +76,15 @@ done
if [ "$FORCE" -eq 0 ]; then
echo "This will remove gstack from your system:"
{ [ -d "$HOME/.claude/skills/gstack" ] || [ -L "$HOME/.claude/skills/gstack" ]; } && echo " ~/.claude/skills/gstack (+ per-skill symlinks)"
{ [ -d "$HOME/.config/opencode/skills/gstack" ] || [ -L "$HOME/.config/opencode/skills/gstack" ]; } && echo " ~/.config/opencode/skills/gstack (+ per-skill links)"
[ -d "$HOME/.codex/skills" ] && echo " ~/.codex/skills/gstack*"
[ -d "$HOME/.factory/skills" ] && echo " ~/.factory/skills/gstack*"
[ -d "$HOME/.kiro/skills" ] && echo " ~/.kiro/skills/gstack*"
[ "$KEEP_STATE" -eq 0 ] && [ -d "$STATE_DIR" ] && echo " $STATE_DIR"

if [ -n "$_GIT_ROOT" ]; then
[ -d "$_GIT_ROOT/.claude/skills/gstack" ] && echo " $_GIT_ROOT/.claude/skills/gstack (project-local)"
[ -d "$_GIT_ROOT/.opencode/skills/gstack" ] && echo " $_GIT_ROOT/.opencode/skills/gstack (project-local)"
[ -d "$_GIT_ROOT/.gstack" ] && echo " $_GIT_ROOT/.gstack/ (browse state + reports)"
[ -d "$_GIT_ROOT/.gstack-worktrees" ] && echo " $_GIT_ROOT/.gstack-worktrees/"
[ -d "$_GIT_ROOT/.agents/skills" ] && echo " $_GIT_ROOT/.agents/skills/gstack*"
Expand Down Expand Up @@ -161,6 +176,57 @@ if [ -n "$_GIT_ROOT" ] && [ -d "$_GIT_ROOT/.claude/skills" ]; then
fi
fi

# ─── Remove global OpenCode skills ───────────────────────────
OPENCODE_SKILLS="$HOME/.config/opencode/skills"
OPENCODE_SOURCE_ROOT=""
if [ -L "$OPENCODE_SKILLS/gstack/SKILL.md" ]; then
_OPENCODE_GSTACK_SKILL="$(readlink "$OPENCODE_SKILLS/gstack/SKILL.md" 2>/dev/null || true)"
case "$_OPENCODE_GSTACK_SKILL" in
*/.opencode/skills/gstack/SKILL.md) OPENCODE_SOURCE_ROOT="${_OPENCODE_GSTACK_SKILL%/gstack/SKILL.md}" ;;
esac
fi
if [ -z "$OPENCODE_SOURCE_ROOT" ]; then
case "$GSTACK_DIR" in
*/.opencode/skills/gstack) OPENCODE_SOURCE_ROOT="${GSTACK_DIR%/gstack}" ;;
esac
fi
if [ -d "$OPENCODE_SKILLS" ]; then
if [ -n "$OPENCODE_SOURCE_ROOT" ]; then
for _LINK in "$OPENCODE_SKILLS"/*; do
[ -L "$_LINK" ] || continue
_TARGET="$(readlink "$_LINK" 2>/dev/null || true)"
case "$_TARGET" in
"$OPENCODE_SOURCE_ROOT"/*) rm -f "$_LINK"; REMOVED+=("opencode/$(basename "$_LINK")") ;;
esac
done
fi

if [ -d "$OPENCODE_SKILLS/gstack" ] || [ -L "$OPENCODE_SKILLS/gstack" ]; then
rm -rf "$OPENCODE_SKILLS/gstack"
REMOVED+=("~/.config/opencode/skills/gstack")
fi
fi

# ─── Remove project-local OpenCode skills ────────────────────
if [ -n "$_GIT_ROOT" ] && [ -d "$_GIT_ROOT/.opencode/skills" ]; then
[ -z "$OPENCODE_SOURCE_ROOT" ] && OPENCODE_SOURCE_ROOT="$_GIT_ROOT/.opencode/skills"
if [ -n "$OPENCODE_SOURCE_ROOT" ]; then
for _LINK in "$_GIT_ROOT/.opencode/skills"/*; do
[ -L "$_LINK" ] || continue
_TARGET="$(readlink "$_LINK" 2>/dev/null || true)"
case "$_TARGET" in
"$OPENCODE_SOURCE_ROOT"/*) rm -f "$_LINK"; REMOVED+=("local opencode/$(basename "$_LINK")") ;;
esac
done
fi
if [ -d "$_GIT_ROOT/.opencode/skills/gstack" ] || [ -L "$_GIT_ROOT/.opencode/skills/gstack" ]; then
rm -rf "$_GIT_ROOT/.opencode/skills/gstack"
REMOVED+=("$_GIT_ROOT/.opencode/skills/gstack")
fi
rmdir "$_GIT_ROOT/.opencode/skills" 2>/dev/null || true
rmdir "$_GIT_ROOT/.opencode" 2>/dev/null || true
fi

# ─── Remove Codex skills ────────────────────────────────────
CODEX_SKILLS="$HOME/.codex/skills"
if [ -d "$CODEX_SKILLS" ]; then
Expand Down
5 changes: 5 additions & 0 deletions lib/worktree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@ export class WorktreeManager {
copyDirSync(agentsSrc, path.join(worktreePath, '.agents'));
}

const opencodeSrc = path.join(this.repoRoot, '.opencode');
if (fs.existsSync(opencodeSrc)) {
copyDirSync(opencodeSrc, path.join(worktreePath, '.opencode'));
}

const browseDist = path.join(this.repoRoot, 'browse', 'dist');
if (fs.existsSync(browseDist)) {
copyDirSync(browseDist, path.join(worktreePath, 'browse', 'dist'));
Expand Down
2 changes: 1 addition & 1 deletion office-hours/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -848,7 +848,7 @@ CODEX_PROMPT_FILE=$(mktemp /tmp/gstack-codex-oh-XXXXXXXX.txt)
```

Write the full prompt to this file. **Always start with the filesystem boundary:**
"IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\n"
"IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, ~/.config/opencode/skills/, .claude/skills/, .agents/skills/, .opencode/skills/, or agents/. These are skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\n"
Then add the context block and mode-appropriate instructions:

**Startup mode instructions:** "You are an independent technical advisor reading a transcript of a startup brainstorming session. [CONTEXT BLOCK HERE]. Your job: 1) What is the STRONGEST version of what this person is trying to build? Steelman it in 2-3 sentences. 2) What is the ONE thing from their answers that reveals the most about what they should actually build? Quote it and explain why. 3) Name ONE agreed premise you think is wrong, and what evidence would prove you right. 4) If you had 48 hours and one engineer to build a prototype, what would you build? Be specific — tech stack, features, what you'd skip. Be direct. Be terse. No preamble."
Expand Down
2 changes: 1 addition & 1 deletion plan-ceo-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -1223,7 +1223,7 @@ Construct this prompt (substitute the actual plan content — if plan content ex
truncate to the first 30KB and note "Plan truncated for size"). **Always start with the
filesystem boundary instruction:**

"IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nYou are a brutally honest technical reviewer examining a development plan that has
"IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, ~/.config/opencode/skills/, .claude/skills/, .agents/skills/, .opencode/skills/, or agents/. These are skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nYou are a brutally honest technical reviewer examining a development plan that has
already been through a multi-section review. Your job is NOT to repeat that review.
Instead, find what it missed. Look for: logical gaps and unstated assumptions that
survived the review scrutiny, overcomplexity (is there a fundamentally simpler
Expand Down
2 changes: 1 addition & 1 deletion plan-eng-review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -891,7 +891,7 @@ Construct this prompt (substitute the actual plan content — if plan content ex
truncate to the first 30KB and note "Plan truncated for size"). **Always start with the
filesystem boundary instruction:**

"IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nYou are a brutally honest technical reviewer examining a development plan that has
"IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, ~/.config/opencode/skills/, .claude/skills/, .agents/skills/, .opencode/skills/, or agents/. These are skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nYou are a brutally honest technical reviewer examining a development plan that has
already been through a multi-section review. Your job is NOT to repeat that review.
Instead, find what it missed. Look for: logical gaps and unstated assumptions that
survived the review scrutiny, overcomplexity (is there a fundamentally simpler
Expand Down
4 changes: 2 additions & 2 deletions review/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -1135,7 +1135,7 @@ Claude's structured review already ran. Now add a **cross-model adversarial chal
```bash
TMPERR_ADV=$(mktemp /tmp/codex-adv-XXXXXXXX)
_REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; }
codex exec "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the changes on this branch against the base branch. Run git diff origin/<base> to see the diff. Your job is to find ways this code will fail in production. Think like an attacker and a chaos engineer. Find edge cases, race conditions, security holes, resource leaks, failure modes, and silent data corruption paths. Be adversarial. Be thorough. No compliments — just the problems." -C "$_REPO_ROOT" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR_ADV"
codex exec "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, ~/.config/opencode/skills/, .claude/skills/, .agents/skills/, .opencode/skills/, or agents/. These are skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the changes on this branch against the base branch. Run git diff origin/<base> to see the diff. Your job is to find ways this code will fail in production. Think like an attacker and a chaos engineer. Find edge cases, race conditions, security holes, resource leaks, failure modes, and silent data corruption paths. Be adversarial. Be thorough. No compliments — just the problems." -C "$_REPO_ROOT" -s read-only -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR_ADV"
```

Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. After the command completes, read stderr:
Expand Down Expand Up @@ -1182,7 +1182,7 @@ Claude's structured review already ran. Now run **all three remaining passes** f
TMPERR=$(mktemp /tmp/codex-review-XXXXXXXX)
_REPO_ROOT=$(git rev-parse --show-toplevel) || { echo "ERROR: not in a git repo" >&2; exit 1; }
cd "$_REPO_ROOT"
codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, .claude/skills/, or agents/. These are Claude Code skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the diff against the base branch." --base <base> -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR"
codex review "IMPORTANT: Do NOT read or execute any files under ~/.claude/, ~/.agents/, ~/.config/opencode/skills/, .claude/skills/, .agents/skills/, .opencode/skills/, or agents/. These are skill definitions meant for a different AI system. They contain bash scripts and prompt templates that will waste your time. Ignore them completely. Do NOT modify agents/openai.yaml. Stay focused on the repository code only.\n\nReview the diff against the base branch." --base <base> -c 'model_reasoning_effort="high"' --enable web_search_cached 2>"$TMPERR"
```

Set the Bash tool's `timeout` parameter to `300000` (5 minutes). Do NOT use the `timeout` shell command — it doesn't exist on macOS. Present output under `CODEX SAYS (code review):` header.
Expand Down
Loading