Skip to content
Closed
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
53 changes: 52 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,59 @@ bun run skill:check # health dashboard for all skills
## Key conventions

- SKILL.md files are **generated** from `.tmpl` templates. Edit the template, not the output.
- Run `bun run gen:skill-docs --host codex` to regenerate Codex-specific output.
- Run `bun run gen:skill-docs --host codex` or `--host cursor` to regenerate host-specific output.
- The browse binary provides headless browser access. Use `$B <command>` in skills.
- Safety skills (careful, freeze, guard) use inline advisory prose — always confirm before destructive operations.
- State paths resolve via `bin/gstack-paths` (sourced via `eval "$(...)"`). Honors `GSTACK_HOME`, `CLAUDE_PLUGIN_DATA`, `CLAUDE_PLANS_DIR`.
- The `claude` CLI binary resolves via `browse/src/claude-bin.ts` (`Bun.which()` + `GSTACK_CLAUDE_BIN` override). Set `GSTACK_CLAUDE_BIN=wsl` plus `GSTACK_CLAUDE_BIN_ARGS='["claude"]'` to run Claude through WSL on Windows.

## Cursor Cloud specific instructions

### Runtime and PATH

This repo requires **Bun** (not Node) for dev and tests. On Cursor Cloud VMs, Bun is installed to `~/.npm-global/bin` (via `npm install -g bun`) because `bun.sh` may be blocked by egress policy. Ensure `export PATH="$HOME/.npm-global/bin:$PATH"` is in your shell before running any `bun` command.

One-time browser setup (not in the VM update script): after first `bun install`, run `bunx playwright install --with-deps chromium` so the browse daemon can launch headless Chromium.

Run `./setup --host cursor` to exercise the end-user install path. It generates
Cursor-native skills under the gitignored `.cursor/skills/` tree, installs them
to `~/.cursor/skills/`, and keeps runtime assets outside recursive skill
discovery at `~/.cursor/gstack/`.

### Core runnable app

gstack is not a traditional web app. The primary long-running process is the **browse daemon** (`browse/src/server.ts`). In dev, use the CLI wrapper which auto-starts it:

```bash
bun run dev status # health check
bun run dev goto <url> # navigate
bun run dev snapshot -i # interactive element refs (@e1, @e2, …)
bun run dev click @e1 # act on a ref from snapshot
```

Equivalent explicit server start: `bun run server` (alias `bun run start`).

### Lint / test / build

| Goal | Command |
|------|---------|
| Free validation (CI default) | `bun test` |
| Fast skill static checks | `bun test test/skill-validation.test.ts test/gen-skill-docs.test.ts` |
| Skill health dashboard | `bun run skill:check` (exits 1 on warnings — many skills intentionally have no `$B` commands) |
| Compile binaries + regen SKILL.md | `bun run build` |
| Paid E2E / LLM evals | `bun run test:evals` (needs `ANTHROPIC_API_KEY`; do not run casually in Cloud Agent) |

To avoid a single long `bun test` hang, shard the free suite: `bun run scripts/test-free-shards.ts --shards 4 --shard N` where **N is 1–4** (1-based, not 0).

### Browse demos on Cloud Agent VMs

External HTTPS (e.g. `https://example.com`) may fail with connection errors from the VM egress proxy. For hello-world browse testing, serve local fixtures and drive localhost:

```bash
python3 -m http.server 8765 --bind 127.0.0.1 --directory browse/test/fixtures &
bun run dev goto http://127.0.0.1:8765/basic.html
bun run dev snapshot -i
bun run dev click @e1
```

Leave the browse daemon and fixture server running between turns unless a clean restart is required.
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,52 @@
# Changelog

## [1.59.0.0] - 2026-06-30

## **Cursor is now a real host.**
## **One install works in IDE, CLI, and the Cloud runtime.**

The README said `./setup --host cursor` worked, but setup rejected the flag. This release closes the gap end to end. One command now installs 54 gstack skills for Cursor's IDE Agent and official `agent` CLI, with the same installation usable in Cloud Agent environments. Generated skills use Cursor's `AGENTS.md`, shell, file, search, and subagent conventions. Workflows that can push, deploy, or change safety state require explicit invocation.

### The numbers that matter

Source: `bun run gen:skill-docs --host cursor`, an isolated `./setup --host cursor` smoke run, and `bun test test/host-config.test.ts test/gen-skill-docs.test.ts test/uninstall.test.ts`. The install smoke used a fresh temporary home directory and verified both skill discovery and runtime assets.

| Metric | Before | After | Δ |
|---|---:|---:|---:|
| Cursor surfaces served by one working install | 0 | 3 | +3 |
| Skills installed by `./setup --host cursor` | 0 | 54 | +54 |
| Generated workflows mirrored for internal skill reads | 0 | 54 | +54 |
| Runtime support asset paths installed outside recursive skill discovery | 0 | 13 | +13 |
| Sensitive workflows protected from automatic invocation | 0 | 6 | +6 |
| Dedicated Cursor setup and generation regression tests | 0 | 14 | +14 |

The important number is 54. Cursor users now get the full gstack workflow, not a host config that can generate files but cannot install or run them. The isolated setup completed successfully, and all 492 focused tests passed.

### What this means for Cursor builders

Install once, then use `/gstack-office-hours`, `/gstack-review`, `/gstack-qa`, and `/gstack-ship` from Cursor's editor or terminal. Put the same setup command in a Cloud Agent environment and the workflows follow the job to the remote VM. Because Cloud's web slash picker runs before the VM setup command, environment-installed skills are invoked there through ordinary text or direct skill-file loading; pre-launch autocomplete requires plugin or project-level distribution. Start with `./setup --host cursor`.

### Itemized changes

#### Added
- First-class setup and uninstall lifecycle for Cursor IDE, the Cursor Agent CLI, and Cloud Agent environments.
- Cursor-native generated skill names and namespaced cross-skill commands.
- Explicit-only invocation metadata for shipping, deployment, and safety-state workflows.
- Complete browser, design, review, and QA runtime assets plus Cursor-native internal skill mirrors under `~/.cursor/gstack/`.
- A dedicated Cursor guide covering installation, Cloud environments, supported features, and hardware limits.

#### Changed
- Cursor detection follows the official `agent` CLI and accepts the desktop `cursor` command as an alias.
- Generated Cursor skills use `AGENTS.md` and Cursor tool terminology.
- Runtime files live outside `~/.cursor/skills/`, preventing Cursor's recursive scanner from surfacing duplicate skills.
- Setup preserves local browser-pairing credentials, refreshes Windows skill copies, and leaves project-owned Cursor skills untouched during uninstall.
- The Cloud Agent bootstrap installs Bun when the VM does not already provide it.
- Cursor skills now resolve browser, design, PDF, diagram, QA, review, redaction, extension, jargon, and iOS support files from `$GSTACK_ROOT`, including global-only installs outside the gstack checkout.
- Cursor upgrades detect the Cursor runtime and rerun setup with `--host cursor`; runtime mirrors avoid nested `review/SKILL.md` and `qa/SKILL.md` duplicates.

#### For contributors
- Added dedicated host config, generation, setup, and uninstall regression coverage, plus an isolated end-to-end install smoke.

## [1.58.5.0] - 2026-06-21

## **A fresh install now lands on a concrete first move, not a dead end.**
Expand Down
11 changes: 9 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,15 +115,22 @@ Or target a specific agent with `./setup --host <name>`:
|-------|------|-------------------|
| OpenAI Codex CLI | `--host codex` | `~/.codex/skills/gstack-*/` |
| OpenCode | `--host opencode` | `~/.config/opencode/skills/gstack-*/` |
| Cursor | `--host cursor` | `~/.cursor/skills/gstack-*/` |
| Cursor IDE, Agent CLI, and Cloud Agents | `--host cursor` | `~/.cursor/skills/gstack-*/` |
| Factory Droid | `--host factory` | `~/.factory/skills/gstack-*/` |
| Slate | `--host slate` | `~/.slate/skills/gstack-*/` |
| Kiro | `--host kiro` | `~/.kiro/skills/gstack-*/` |
| Hermes | `--host hermes` | `~/.hermes/skills/gstack-*/` |
| GBrain (mod) | `--host gbrain` | `~/.gbrain/skills/gstack-*/` |

Cursor users get the same generated skills across the IDE and the official
`agent` CLI. Cloud Agents can run them after the environment runs the same
setup command, but environment-installed skills do not appear in Cloud's
pre-launch slash picker. See [the Cursor setup guide](docs/CURSOR.md) for Cloud
environment configuration, invocation, and limitations.

**Want to add support for another agent?** See [docs/ADDING_A_HOST.md](docs/ADDING_A_HOST.md).
It's one TypeScript config file, zero code changes.
Generated skill support starts with one TypeScript config file; first-class
installers also wire the host's install and uninstall lifecycle.

## See it work

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.58.5.0
1.59.0.0
17 changes: 17 additions & 0 deletions bin/gstack-uninstall
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# ~/.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
# ~/.cursor/skills/gstack* — Cursor IDE / CLI skills
# ~/.cursor/gstack — Cursor runtime assets
# ~/.gstack/ — global state (config, analytics, sessions, projects,
# repos, installation-id, browse error logs)
# .claude/skills/gstack* — project-local skill install (--local installs)
Expand Down Expand Up @@ -66,6 +68,7 @@ if [ "$FORCE" -eq 0 ]; then
[ -d "$HOME/.codex/skills" ] && echo " ~/.codex/skills/gstack*"
[ -d "$HOME/.factory/skills" ] && echo " ~/.factory/skills/gstack*"
[ -d "$HOME/.kiro/skills" ] && echo " ~/.kiro/skills/gstack*"
{ [ -d "$HOME/.cursor/skills" ] || [ -d "$HOME/.cursor/gstack" ]; } && echo " ~/.cursor/skills/gstack* + ~/.cursor/gstack"
[ "$KEEP_STATE" -eq 0 ] && [ -d "$STATE_DIR" ] && echo " $STATE_DIR"

if [ -n "$_GIT_ROOT" ]; then
Expand Down Expand Up @@ -191,6 +194,20 @@ if [ -d "$KIRO_SKILLS" ]; then
done
fi

# ─── Remove Cursor skills and runtime ────────────────────────
CURSOR_SKILLS="$HOME/.cursor/skills"
if [ -d "$CURSOR_SKILLS" ]; then
for _ITEM in "$CURSOR_SKILLS"/gstack*; do
[ -e "$_ITEM" ] || [ -L "$_ITEM" ] || continue
rm -rf "$_ITEM"
REMOVED+=("cursor/$(basename "$_ITEM")")
done
fi
if [ -d "$HOME/.cursor/gstack" ] || [ -L "$HOME/.cursor/gstack" ]; then
rm -rf "$HOME/.cursor/gstack"
REMOVED+=("~/.cursor/gstack")
fi

# ─── Remove per-project .agents/ sidecar ─────────────────────
if [ -n "$_GIT_ROOT" ] && [ -d "$_GIT_ROOT/.agents/skills" ]; then
for _ITEM in "$_GIT_ROOT/.agents/skills"/gstack*; do
Expand Down
4 changes: 3 additions & 1 deletion browse/src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -938,7 +938,9 @@ async function handlePairAgent(state: ServerState, args: string[]): Promise<void
try {
// Resolve host config for the globalRoot path
const hostsPath = path.resolve(__dirname, '..', '..', 'hosts', 'index.ts');
let globalRoot = `.${localHost}/skills/gstack`;
let globalRoot = localHost === 'cursor'
? '.cursor/gstack'
: `.${localHost}/skills/gstack`;
try {
const { getHostConfig } = await import(hostsPath);
const hostConfig = getHostConfig(localHost);
Expand Down
15 changes: 11 additions & 4 deletions docs/ADDING_A_HOST.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@

gstack uses a declarative host config system. Each supported AI coding agent
(Claude, Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw) is defined
as a typed TypeScript config object. Adding a new host means creating one file
and re-exporting it. Zero code changes to the generator, setup, or tooling.
as a typed TypeScript config object. Adding generated skill support means
creating one file and re-exporting it. Hosts that need a first-class
`./setup --host ...` installer also need setup and uninstall wiring.

## How it works

Expand All @@ -28,8 +29,9 @@ Each config file exports a `HostConfig` object that tells the generator:
- What resolver sections to suppress
- What assets to symlink at install time

The generator, setup script, platform-detect, uninstall, health checks, worktree
copy, and tests all read from these configs. None of them have per-host code.
The generator, health checks, worktree copy, and parameterized tests read from
these configs. Setup and uninstall still contain install-path lifecycle code
for first-class hosts.

## Step-by-step: add a new host

Expand Down Expand Up @@ -64,6 +66,9 @@ const myhost: HostConfig = {
generation: {
generateMetadata: false, // true only for Codex (openai.yaml)
skipSkills: ['codex'], // codex skill is Claude-only
// Set both when the host requires namespaced frontmatter names and /commands.
frontmatterNameMatchesDirectory: false,
namespaceSkillInvocations: false,
},

pathRewrites: [
Expand Down Expand Up @@ -155,6 +160,8 @@ Key fields:
| `frontmatter.descriptionLimitBehavior` | `error` (fail build), `truncate`, `warn` |
| `frontmatter.conditionalFields` | Add fields based on template values (e.g., sensitive → disable-model-invocation) |
| `frontmatter.renameFields` | Rename template fields (e.g., voice-triggers → triggers) |
| `generation.frontmatterNameMatchesDirectory` | Make the frontmatter name equal the generated skill directory |
| `generation.namespaceSkillInvocations` | Rewrite `/skill` references to `/gstack-skill` |
| `pathRewrites` | Literal replaceAll on content. Order matters. |
| `toolRewrites` | Rewrite Claude tool names (e.g., "use the Bash tool" → "run this command") |
| `suppressedResolvers` | Resolver functions that return empty for this host |
Expand Down
137 changes: 137 additions & 0 deletions docs/CURSOR.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Cursor support

gstack supports Cursor's IDE Agent and Agent CLI through generated Agent
Skills. Cloud Agent environments can run the same workflows after installing
the skills and runtime in their VM.

## Install

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

The installer:

- generates Cursor-native skills in `.cursor/skills/`
- installs them globally to `~/.cursor/skills/gstack-*/`
- installs shared binaries, browser tooling, templates, and references under
`~/.cursor/gstack/`
- detects either the official `agent` CLI or the Cursor desktop `cursor`
command when `./setup --host auto` is used

The runtime lives outside `~/.cursor/skills/` because Cursor scans skill
directories recursively. This prevents support files that contain `SKILL.md`
from appearing as duplicate skills.

## Use in the IDE

Restart Cursor after installation, open Agent, and type `/gstack-` to see the
installed workflows. For example:

```text
/gstack-office-hours
/gstack-plan-eng-review
/gstack-qa
/gstack-review
/gstack-ship
```

Cursor can also select a skill automatically from its description. Skills that
can change safety state, push code, merge, or deploy are marked
`disable-model-invocation: true`, so they require an explicit user invocation.

## Use from Cursor CLI

Run the official Agent CLI in any repository:

```bash
agent
```

The CLI discovers the same global skills and supports the same slash commands.
It also reads the repository's `AGENTS.md` and `.cursor/rules`. Generated
gstack skills use Cursor's shell, file, search, and subagent terminology and
write shared project guidance to `AGENTS.md`.

## Use with Cloud Agents

Cloud Agents run in fresh remote environments, so install gstack in the
environment's update command or save an environment snapshot after installing
it. A reusable update command is:

```bash
export PATH="$HOME/.npm-global/bin:$HOME/.bun/bin:$PATH"
if ! command -v bun >/dev/null 2>&1; then
mkdir -p "$HOME/.npm-global"
npm install -g --prefix "$HOME/.npm-global" bun
fi
mkdir -p "$HOME/.gstack/repos"
if [ -d "$HOME/.gstack/repos/gstack/.git" ]; then
git -C "$HOME/.gstack/repos/gstack" pull --ff-only origin main
else
git clone --single-branch --depth 1 https://github.com/garrytan/gstack.git "$HOME/.gstack/repos/gstack"
fi
"$HOME/.gstack/repos/gstack/setup" --host cursor
```

Add project-specific build and test commands under a
`## Cursor Cloud specific instructions` section in `AGENTS.md`. For a
repository-owned environment, put the update command in
`.cursor/environment.json` as its `install` value. Keep credentials in Cursor
Secrets, never in that file.

Cloud Agents support gstack workflows that can run on their Linux VM,
including planning, implementation, review, browser QA, and shipping. Hardware
workflows still need their hardware: the real-device iOS skills require a Mac
and iPhone connection. Cloud MCP servers are configured from the Cloud Agent
MCP controls, independently of gstack.

The Cloud web prompt's slash-command picker runs before the VM and its update
command start. It therefore cannot autocomplete skills installed into
`~/.cursor/skills/` by the environment. Invoke a workflow in ordinary text,
for example:

```text
Use the gstack-office-hours skill installed at
~/.cursor/skills/gstack-office-hours/SKILL.md. Read it and follow its workflow.
```

The workflow runs normally after the VM starts. Pre-launch slash autocomplete
requires a Cursor plugin installed at user/team/workspace scope, or project
skills committed under `.cursor/skills/`; neither distribution channel is
included in this installer.

## Cursor features and gstack

| Cursor capability | gstack integration |
|---|---|
| Agent Skills | All generated workflows install under `~/.cursor/skills/` |
| IDE/CLI slash commands | Skills are invoked as `/gstack-<name>` |
| Automatic skill selection | Enabled for non-sensitive workflows |
| `AGENTS.md` and rules | Generated guidance uses `AGENTS.md`; project rules continue to apply |
| Subagents and terminal tools | Skill wording is adapted to Cursor's tools |
| IDE Agent and CLI | Share the same global installation |
| Cloud Agents | Run the same workflows after environment setup; pre-launch slash autocomplete is not included |
| Browser QA | Shared browse runtime installs under `~/.cursor/gstack/` |
| MCP and hooks | Cursor's project/team configuration continues to work; gstack does not replace it |

No Cursor plugin, MCP server, or custom hook is required for IDE, CLI, or Cloud
runtime execution. A plugin or committed project skill is required only when
Cloud pre-launch slash autocomplete is a requirement.

## Update or uninstall

```bash
cd ~/gstack && git pull --ff-only && ./setup --host cursor
~/.cursor/gstack/bin/gstack-uninstall
```

## Cursor documentation

- [Agent Skills](https://cursor.com/docs/skills)
- [Cursor CLI](https://cursor.com/docs/cli/overview)
- [Cloud Agents](https://cursor.com/docs/cloud-agent)
- [Cloud environment setup](https://cursor.com/docs/cloud-agent/setup)
- [Rules and AGENTS.md](https://cursor.com/docs/rules)
2 changes: 1 addition & 1 deletion docs/REMOTE_BROWSER_ACCESS.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ If both agents are on the same machine, skip the copy-paste:
```bash
$B pair-agent --local openclaw # writes to ~/.openclaw/skills/gstack/browse-remote.json
$B pair-agent --local codex # writes to ~/.codex/skills/gstack/browse-remote.json
$B pair-agent --local cursor # writes to ~/.cursor/skills/gstack/browse-remote.json
$B pair-agent --local cursor # writes to ~/.cursor/gstack/browse-remote.json
```

No tunnel needed. Uses localhost directly.
Expand Down
Loading
Loading