mirror of
https://github.com/garrytan/gstack.git
synced 2026-05-18 18:32:28 +08:00
Merge branch 'main' into garrytan/team-supabase-store
Brings in 48 commits from main (v0.15.7–v0.15.16): deterministic slugs, TabSession refactor, pair-agent tunnel fix, content security layers, community security wave, team-friendly install, interactive snapshots. Conflict resolution: - .gitignore: merged both sides (kept .factory/ + added .kiro/.opencode/ .slate/.cursor/.openclaw/ from main) - open-gstack-browser/SKILL.md: accepted main (renamed from .factory/) - setup-team-sync/SKILL.md: regenerated via gen:skill-docs - test/fixtures/golden/*: updated golden baselines for ship SKILL.md - codex-ship-SKILL.md: accepted main (renamed from .factory/) - package.json version: synced to VERSION (0.15.16.0) - bin/gstack-uninstall: check settings file exists before claiming SessionStart hook removal (fixes false positive on clean systems) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
177
CONTRIBUTING.md
177
CONTRIBUTING.md
@@ -20,26 +20,19 @@ Now edit any `SKILL.md`, invoke it in Claude Code (e.g. `/review`), and see your
|
||||
bin/dev-teardown # deactivate — back to your global install
|
||||
```
|
||||
|
||||
## Contributor mode
|
||||
## Operational self-improvement
|
||||
|
||||
Contributor mode turns gstack into a self-improving tool. Enable it and Claude Code
|
||||
will periodically reflect on its gstack experience — rating it 0-10 at the end of
|
||||
each major workflow step. When something isn't a 10, it thinks about why and files
|
||||
a report to `~/.gstack/contributor-logs/` with what happened, repro steps, and what
|
||||
would make it better.
|
||||
gstack automatically learns from failures. At the end of every skill session, the agent
|
||||
reflects on what went wrong (CLI errors, wrong approaches, project quirks) and logs
|
||||
operational learnings to `~/.gstack/projects/{slug}/learnings.jsonl`. Future sessions
|
||||
surface these learnings automatically, so gstack gets smarter on your codebase over time.
|
||||
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-config set gstack_contributor true
|
||||
```
|
||||
|
||||
The logs are for **you**. When something bugs you enough to fix, the report is
|
||||
already written. Fork gstack, symlink your fork into the project where you hit
|
||||
the issue, fix it, and open a PR.
|
||||
No setup needed. Learnings are logged automatically. View them with `/learn`.
|
||||
|
||||
### The contributor workflow
|
||||
|
||||
1. **Use gstack normally** — contributor mode reflects and logs issues automatically
|
||||
2. **Check your logs:** `ls ~/.gstack/contributor-logs/`
|
||||
1. **Use gstack normally** — operational learnings are captured automatically
|
||||
2. **Check your learnings:** `/learn` or `ls ~/.gstack/projects/*/learnings.jsonl`
|
||||
3. **Fork and clone gstack** (if you haven't already)
|
||||
4. **Symlink your fork into the project where you hit the bug:**
|
||||
```bash
|
||||
@@ -47,8 +40,8 @@ the issue, fix it, and open a PR.
|
||||
ln -sfn /path/to/your/gstack-fork .claude/skills/gstack
|
||||
cd .claude/skills/gstack && bun install && bun run build && ./setup
|
||||
```
|
||||
Setup creates the per-skill symlinks (`qa -> gstack/qa`, etc.) and asks your
|
||||
prefix preference. Pass `--no-prefix` to skip the prompt and use short names.
|
||||
Setup creates per-skill directories with SKILL.md symlinks inside (`qa/SKILL.md -> gstack/qa/SKILL.md`)
|
||||
and asks your prefix preference. Pass `--no-prefix` to skip the prompt and use short names.
|
||||
5. **Fix the issue** — your changes are live immediately in this project
|
||||
6. **Test by actually using gstack** — do the thing that annoyed you, verify it's fixed
|
||||
7. **Open a PR from your fork**
|
||||
@@ -71,9 +64,11 @@ your local edits instead of the global install.
|
||||
gstack/ <- your working tree
|
||||
├── .claude/skills/ <- created by dev-setup (gitignored)
|
||||
│ ├── gstack -> ../../ <- symlink back to repo root
|
||||
│ ├── review -> gstack/review <- short names (default)
|
||||
│ ├── ship -> gstack/ship <- or gstack-review, gstack-ship if --prefix
|
||||
│ └── ... <- one symlink per skill
|
||||
│ ├── review/ <- real directory (short name, default)
|
||||
│ │ └── SKILL.md -> gstack/review/SKILL.md
|
||||
│ ├── ship/ <- or gstack-review/, gstack-ship/ if --prefix
|
||||
│ │ └── SKILL.md -> gstack/ship/SKILL.md
|
||||
│ └── ... <- one directory per skill
|
||||
├── review/
|
||||
│ └── SKILL.md <- edit this, test with /review
|
||||
├── ship/
|
||||
@@ -84,7 +79,9 @@ gstack/ <- your working tree
|
||||
└── ...
|
||||
```
|
||||
|
||||
Skill symlink names depend on your prefix setting (`~/.gstack/config.yaml`).
|
||||
Setup creates real directories (not symlinks) at the top level with a SKILL.md
|
||||
symlink inside. This ensures Claude discovers them as top-level skills, not nested
|
||||
under `gstack/`. Names depend on your prefix setting (`~/.gstack/config.yaml`).
|
||||
Short names (`/review`, `/ship`) are the default. Run `./setup --prefix` if you
|
||||
prefer namespaced names (`/gstack-review`, `/gstack-ship`).
|
||||
|
||||
@@ -222,11 +219,10 @@ SKILL.md files are **generated** from `.tmpl` templates. Don't edit the `.md` di
|
||||
# 1. Edit the template
|
||||
vim SKILL.md.tmpl # or browse/SKILL.md.tmpl
|
||||
|
||||
# 2. Regenerate for both hosts
|
||||
bun run gen:skill-docs
|
||||
bun run gen:skill-docs --host codex
|
||||
# 2. Regenerate for all hosts
|
||||
bun run gen:skill-docs --host all
|
||||
|
||||
# 3. Check health (reports both Claude and Codex)
|
||||
# 3. Check health (reports all hosts)
|
||||
bun run skill:check
|
||||
|
||||
# Or use watch mode — auto-regenerates on save
|
||||
@@ -237,59 +233,74 @@ For template authoring best practices (natural language over bash-isms, dynamic
|
||||
|
||||
To add a browse command, add it to `browse/src/commands.ts`. To add a snapshot flag, add it to `SNAPSHOT_FLAGS` in `browse/src/snapshot.ts`. Then rebuild.
|
||||
|
||||
## Dual-host development (Claude + Codex)
|
||||
## Multi-host development
|
||||
|
||||
gstack generates SKILL.md files for two hosts: **Claude** (`.claude/skills/`) and **Codex** (`.agents/skills/`). Every template change needs to be generated for both.
|
||||
gstack generates SKILL.md files for 8 hosts from one set of `.tmpl` templates.
|
||||
Each host is a typed config in `hosts/*.ts`. The generator reads these configs
|
||||
to produce host-appropriate output (different frontmatter, paths, tool names).
|
||||
|
||||
### Generating for both hosts
|
||||
**Supported hosts:** Claude (primary), Codex, Factory, Kiro, OpenCode, Slate, Cursor, OpenClaw.
|
||||
|
||||
### Generating for all hosts
|
||||
|
||||
```bash
|
||||
# Generate Claude output (default)
|
||||
bun run gen:skill-docs
|
||||
# Generate for a specific host
|
||||
bun run gen:skill-docs # Claude (default)
|
||||
bun run gen:skill-docs --host codex # Codex
|
||||
bun run gen:skill-docs --host opencode # OpenCode
|
||||
bun run gen:skill-docs --host all # All 8 hosts
|
||||
|
||||
# Generate Codex output
|
||||
bun run gen:skill-docs --host codex
|
||||
# --host agents is an alias for --host codex
|
||||
|
||||
# Or use build, which does both + compiles binaries
|
||||
# Or use build, which does all hosts + compiles binaries
|
||||
bun run build
|
||||
```
|
||||
|
||||
### What changes between hosts
|
||||
|
||||
| Aspect | Claude | Codex |
|
||||
|--------|--------|-------|
|
||||
| Output directory | `{skill}/SKILL.md` | `.agents/skills/gstack-{skill}/SKILL.md` (generated at setup, gitignored) |
|
||||
| Frontmatter | Full (name, description, allowed-tools, hooks, version) | Minimal (name + description only) |
|
||||
| Paths | `~/.claude/skills/gstack` | `$GSTACK_ROOT` (`.agents/skills/gstack` in a repo, otherwise `~/.codex/skills/gstack`) |
|
||||
| Hook skills | `hooks:` frontmatter (enforced by Claude) | Inline safety advisory prose (advisory only) |
|
||||
| `/codex` skill | Included (Claude wraps codex exec) | Excluded (self-referential) |
|
||||
Each host config (`hosts/*.ts`) controls:
|
||||
|
||||
### Testing Codex output
|
||||
| Aspect | Example (Claude vs Codex) |
|
||||
|--------|---------------------------|
|
||||
| Output directory | `{skill}/SKILL.md` vs `.agents/skills/gstack-{skill}/SKILL.md` |
|
||||
| Frontmatter | Full (name, description, hooks, version) vs minimal (name + description) |
|
||||
| Paths | `~/.claude/skills/gstack` vs `$GSTACK_ROOT` |
|
||||
| Tool names | "use the Bash tool" vs same (Factory rewrites to "run this command") |
|
||||
| Hook skills | `hooks:` frontmatter vs inline safety advisory prose |
|
||||
| Suppressed sections | None vs Codex self-invocation sections stripped |
|
||||
|
||||
See `scripts/host-config.ts` for the full `HostConfig` interface.
|
||||
|
||||
### Testing host output
|
||||
|
||||
```bash
|
||||
# Run all static tests (includes Codex validation)
|
||||
# Run all static tests (includes parameterized smoke tests for all hosts)
|
||||
bun test
|
||||
|
||||
# Check freshness for both hosts
|
||||
bun run gen:skill-docs --dry-run
|
||||
bun run gen:skill-docs --host codex --dry-run
|
||||
# Check freshness for all hosts
|
||||
bun run gen:skill-docs --host all --dry-run
|
||||
|
||||
# Health dashboard covers both hosts
|
||||
# Health dashboard covers all hosts
|
||||
bun run skill:check
|
||||
```
|
||||
|
||||
### Dev setup for .agents/
|
||||
### Adding a new host
|
||||
|
||||
When you run `bin/dev-setup`, it creates symlinks in both `.claude/skills/` and `.agents/skills/` (if applicable), so Codex-compatible agents can discover your dev skills too. The `.agents/` directory is generated at setup time from `.tmpl` templates — it is gitignored and not committed.
|
||||
See [docs/ADDING_A_HOST.md](docs/ADDING_A_HOST.md) for the full guide. Short version:
|
||||
|
||||
1. Create `hosts/myhost.ts` (copy from `hosts/opencode.ts`)
|
||||
2. Add to `hosts/index.ts`
|
||||
3. Add `.myhost/` to `.gitignore`
|
||||
4. Run `bun run gen:skill-docs --host myhost`
|
||||
5. Run `bun test` (parameterized tests auto-cover it)
|
||||
|
||||
Zero generator, setup, or tooling code changes needed.
|
||||
|
||||
### Adding a new skill
|
||||
|
||||
When you add a new skill template, both hosts get it automatically:
|
||||
When you add a new skill template, all hosts get it automatically:
|
||||
1. Create `{skill}/SKILL.md.tmpl`
|
||||
2. Run `bun run gen:skill-docs` (Claude output) and `bun run gen:skill-docs --host codex` (Codex output)
|
||||
3. The dynamic template discovery picks it up — no static list to update
|
||||
4. Commit `{skill}/SKILL.md` — `.agents/` is generated at setup time and gitignored
|
||||
2. Run `bun run gen:skill-docs --host all`
|
||||
3. The dynamic template discovery picks it up, no static list to update
|
||||
4. Commit `{skill}/SKILL.md`, external host output is generated at setup time and gitignored
|
||||
|
||||
## Conductor workspaces
|
||||
|
||||
@@ -330,7 +341,7 @@ ln -sfn /path/to/your/gstack-checkout .claude/skills/gstack
|
||||
### Step 2: Run setup to create per-skill symlinks
|
||||
|
||||
The `gstack` symlink alone isn't enough. Claude Code discovers skills through
|
||||
individual symlinks (`qa -> gstack/qa`, `ship -> gstack/ship`, etc.), not through
|
||||
individual top-level directories (`qa/SKILL.md`, `ship/SKILL.md`, etc.), not through
|
||||
the `gstack/` directory itself. Run `./setup` to create them:
|
||||
|
||||
```bash
|
||||
@@ -354,12 +365,12 @@ Remove the project-local symlink. Claude Code falls back to `~/.claude/skills/gs
|
||||
rm .claude/skills/gstack
|
||||
```
|
||||
|
||||
The per-skill symlinks (`qa`, `ship`, etc.) still point to `gstack/...`, so they'll
|
||||
resolve to the global install automatically.
|
||||
The per-skill directories (`qa/`, `ship/`, etc.) contain SKILL.md symlinks that point
|
||||
to `gstack/...`, so they'll resolve to the global install automatically.
|
||||
|
||||
### Switching prefix mode
|
||||
|
||||
If you vendored gstack with one prefix setting and want to switch:
|
||||
If you installed gstack with one prefix setting and want to switch:
|
||||
|
||||
```bash
|
||||
cd .claude/skills/gstack && ./setup --no-prefix # switch to /qa, /ship
|
||||
@@ -398,6 +409,56 @@ When community PRs accumulate, batch them into themed waves:
|
||||
|
||||
See [PR #205](../../pull/205) (v0.8.3) for the first wave as an example.
|
||||
|
||||
## Upgrade migrations
|
||||
|
||||
When a release changes on-disk state (directory structure, config format, stale
|
||||
files) in ways that `./setup` alone can't fix, add a migration script so existing
|
||||
users get a clean upgrade.
|
||||
|
||||
### When to add a migration
|
||||
|
||||
- Changed how skill directories are created (symlinks vs real dirs)
|
||||
- Renamed or moved config keys in `~/.gstack/config.yaml`
|
||||
- Need to delete orphaned files from a previous version
|
||||
- Changed the format of `~/.gstack/` state files
|
||||
|
||||
Don't add a migration for: new features (users get them automatically), new
|
||||
skills (setup discovers them), or code-only changes (no on-disk state).
|
||||
|
||||
### How to add one
|
||||
|
||||
1. Create `gstack-upgrade/migrations/v{VERSION}.sh` where `{VERSION}` matches
|
||||
the VERSION file for the release that needs the fix.
|
||||
2. Make it executable: `chmod +x gstack-upgrade/migrations/v{VERSION}.sh`
|
||||
3. The script must be **idempotent** (safe to run multiple times) and
|
||||
**non-fatal** (failures are logged but don't block the upgrade).
|
||||
4. Include a comment block at the top explaining what changed, why the
|
||||
migration is needed, and which users are affected.
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
# Migration: v0.15.2.0 — Fix skill directory structure
|
||||
# Affected: users who installed with --no-prefix before v0.15.2.0
|
||||
set -euo pipefail
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")/../.." && pwd)"
|
||||
"$SCRIPT_DIR/bin/gstack-relink" 2>/dev/null || true
|
||||
```
|
||||
|
||||
### How it runs
|
||||
|
||||
During `/gstack-upgrade`, after `./setup` completes (Step 4.75), the upgrade
|
||||
skill scans `gstack-upgrade/migrations/` and runs every `v*.sh` script whose
|
||||
version is newer than the user's old version. Scripts run in version order.
|
||||
Failures are logged but never block the upgrade.
|
||||
|
||||
### Testing migrations
|
||||
|
||||
Migrations are tested as part of `bun test` (tier 1, free). The test suite
|
||||
verifies that all migration scripts in `gstack-upgrade/migrations/` are
|
||||
executable and parse without syntax errors.
|
||||
|
||||
## Shipping your changes
|
||||
|
||||
When you're happy with your skill edits:
|
||||
|
||||
Reference in New Issue
Block a user