mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-05 16:34:00 +01:00
* feat(ubicloud): /ubicloud skill with TTL-named VMs and a reaper, quota preflight, hang watchdog and one committed verify entry point
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: CLAUDE.md names the ratcheted catalog ceiling
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: UBI_OWNER example is a literal value, not a free-text placeholder (INV-3 fence lint)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: the UBI_OWNER example is a neutral value (no thread codes in product prose)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: verify trusts the checkout only, watched commands keep stdin and end the remote session, quota and reap outcomes
verify: .gstack/ubicloud.json is repository content, so its setup script and
pull destinations must resolve inside --src (absolute, ~ and .. refused before
any API call) and a name it lists under pass is forwarded only when the command
line grants it (--pass NAME or --trust-config); --pass never forwards UBICLOUD_*
and refuses non-names. watched: the caller's stdin reaches the remote command,
a command that finished while the clock was read is not a timeout, a hung setup
exits 124, INT/TERM take the ssh session down, and the watchdog ends the
command's session on the VM (setsid + ~/.ubirun-<phase>.sid + pkill -s). Quota:
a cached refusal maximum is trusted for a day, the refusal names its source and
uses the 'vCPU quota exhausted' marker pregate-remote.sh retries on. reap:
returns 1 on a failed list or destroy; TTL suffixes read in base 10 and
UBI_TTL_HOURS takes 0-999. Tests: a fake API that creates plus a fake ssh run
'run' and 'verify' end to end.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: the remote session file is per runner invocation and setsid is optional on the image
Two watched commands on one VM wrote the same ~/.ubirun-<phase>.sid, so a cancel
could end the other's session; the file now carries the runner's pid and is
removed when the command ends. An image without setsid runs the command through
plain bash instead of failing with exit 127.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: pull destinations are rechecked at pull time, verify parses options by arity, a finished command keeps its status, the remote sid outlives the wrapper; docs audit
Pass-2 (Codex adversarial on the delta): an earlier pull could plant a symlink
where a later config pull lands, so under verify every destination is resolved
again (symlinks followed) right before its pull and a refused pull exits 1;
'--dest --trust-config' made an option value act as the trust flag, so verify
parses by arity; a command that finished in the instant before the watchdog's
kill exited 0 and was still reported as 124; the wrapper removed the sid file
while a background child kept the channel open, so the file now stays until
remote_cancel reads it. Docs audit (document-release, edit mode): TTL suffix and
owner rule in TESTING_INTERNALS, the reaper as the exception to 'no sweep', the
docs/skills.md transcript uses a neutral owner; CHANGELOG and the runner header
corrected on the two points it deferred.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: a refused pull destination creates no directory, inside or outside the checkout
inside_dir checked containment after mkdir -p, so a destination under a planted
symlink (escape/new/sub) created the outside directories before being refused.
The nearest existing ancestor is checked first; only an accepted destination is
created, and it is checked again after.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: bin/gstack-ubi has a test lane (it execs the runner and forwards arguments)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: pack ships a linked worktree with a self-contained .git
A worktree's .git is a gitdir pointer into the main repository; on the VM git
could not run, so the remote pregate refused with PREGATE_VM_TREE_MISMATCH
vm=unavailable. pack now replaces it with a bare --single-branch clone of the
checked-out branch (core.bare false, the worktree's index copied in), ~45 MB for
gstack; a detached worktree is refused with the fix named.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: take main's host-conformance C3 fix (#3479) so the remote gate can run on this tree
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* ubicloud: pack skips a split index (its shared half stays in the original git dir)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* CHANGELOG: restore main's released history under the [Unreleased] block (the merge resolution kept only the conflicted span)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* RESTAMP: 1.91.258.0 -> 1.91.259.0 (stamped; queue_mode=stamp-at-merge base=origin/main@7dc2f23192b7 policy=base origin/main@7dc2f23192b7:.gstack/ship-policy.json)
ship, next in queue at 1.91.259.0
STAMP_VERSION: 1.91.259.0
claims: ignored (stamp-at-merge)
stage version: done (wrote 1.91.259.0)
stage release_tool: done (bun scripts/gen-agents-digest.ts)
stage changelog: done (Unreleased -> 1.91.259.0)
stage stamp_paths: skipped (no stamp_paths in policy)
stage mirror: skipped (no mirror in policy)
stage apply: done (4 file(s))
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 3c91fdaf8..e4f4d63ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,6 @@
# Changelog
-## [Unreleased]
+## [1.91.259.0] - 2026-10-26
**New `/ubicloud` skill: the Ubicloud runner moves into gstack with the discipline a shared vCPU quota needs.** Crews ran heavy suites on Ubicloud through a user-scope skill and per-lane wrappers, and paid for it in stray VMs after a machine slept, a project quota at 528 of 512 vCPUs when lanes verified in parallel, verifies that hung for an hour before anyone noticed, and a stale wrapper that skipped a service start. `scripts/ubicloud/ubi-runner.sh` now carries the fixes and `ubicloud/SKILL.md` (entry point `bin/gstack-ubi`) teaches the watched launch; `bun run test:ubicloud` and the remote pregate are unchanged.
diff --git a/VERSION b/VERSION
index c67e9e442..08528ff87 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.91.258.0
+1.91.259.0
diff --git a/agents-digest/gstack-AGENTS.md b/agents-digest/gstack-AGENTS.md
index 4bd43c922..203312cf5 100644
--- a/agents-digest/gstack-AGENTS.md
+++ b/agents-digest/gstack-AGENTS.md
@@ -1,4 +1,4 @@
-# gstack digest v1.91.258.0 — regenerate/re-copy after upgrading gstack
+# gstack digest v1.91.259.0 — regenerate/re-copy after upgrading gstack
Behavioral rules from gstack (https://github.com/garrytan/gstack), compressed
for agent hosts without a full skill install. The full skills add workflows,
diff --git a/node_modules b/node_modules
new file mode 120000
index 000000000..c7990ad12
--- /dev/null
+++ b/node_modules
@@ -0,0 +1 @@
+/workspace/gstack-ubi/node_modules
\ No newline at end of file
diff --git a/package.json b/package.json
index 5e6d56827..0eca459a0 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "gstack",
- "version": "1.91.258",
+ "version": "1.91.259",
"description": "Garry's Stack — Claude Code skills + fast headless browser. One repo, one install, entire AI engineering workflow.",
"license": "MIT",
"type": "module",
FILES: CHANGELOG.md VERSION agents-digest/gstack-AGENTS.md package.json
MERGE_CONDITION: sha=76e86e08a851fb1a19bef9a947bdf0abeb87956d
next: NEW_VERSION=1.91.259.0; commit and push only the stamp diff above (FILES), with no edit of your own: the train's verify accepts the CHANGELOG only as the base's plus this PR's entry re-headed; merge with the expected head 76e86e08a8 and recompute on a stale queue.
GSTACK_RESULT: skill=restamp status=complete run=/workspace/gstack-ubi/.gstack/tmp/restamp-journal.json
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
130 lines
9.3 KiB
Cheetah
130 lines
9.3 KiB
Cheetah
---
|
|
name: gstack
|
|
preamble-tier: 1
|
|
version: 1.2.0
|
|
description: |
|
|
Router for the gstack skill suite. Sends any gstack request to the right skill
|
|
(planning, review, QA, shipping, debugging, docs, security, design). Routes QA by
|
|
intent and browser interaction to /browse. Use when you invoke gstack without a specific
|
|
skill, or ask "which gstack skill fits this?". (gstack)
|
|
allowed-tools:
|
|
- Bash
|
|
- Read
|
|
- AskUserQuestion
|
|
triggers:
|
|
- gstack
|
|
- which gstack skill
|
|
- route this with gstack
|
|
|
|
---
|
|
|
|
{{PREAMBLE}}
|
|
|
|
## Route first
|
|
|
|
This is the gstack router. Its one job is to send the request to the right skill.
|
|
|
|
1. If the request is to test behavior, find bugs, QA or dogfood software → invoke `/qa`,
|
|
or `/qa-only` when the user wants reporting without fixes. These skills select browser,
|
|
API, CLI, job, worker or webhook surfaces before loading their testing instructions.
|
|
An API URL does not imply browser testing. An explicit skill request keeps its authority.
|
|
2. If the request is browser interaction, screenshots, or inspecting a page
|
|
(open a site, take a screenshot, inspect a flow visually) → invoke `/browse`.
|
|
Every gstack browser skill (`/browse`, `/qa`, `/qa-only`, `/design-review`, `/canary`,
|
|
`/benchmark`, `/scrape`) drives the Aside browser first — the user's real browser with
|
|
their real logged-in sessions — and falls back to gstack's own browser when Aside is not
|
|
installed or not running. Route "open the browser" / "import cookies" requests to the
|
|
fallback-browser skills below only when the user is clearly on that path (Linux,
|
|
Windows, or Aside closed); on Aside there is nothing to open or import.
|
|
3. Otherwise, route by the rules below. If nothing matches, answer directly.
|
|
|
|
Best-effort, record which way you routed (never block on it). Set `ROUTE_OUTCOME` to
|
|
`browse` (sent to /browse), `routed` (sent to another skill), or `direct` (answered
|
|
directly, no skill matched), and replace `SESSION_ID` with the value the skill-start
|
|
output echoed:
|
|
```bash
|
|
~/.claude/skills/gstack/bin/gstack-telemetry-log --event-type route --skill gstack --outcome ROUTE_OUTCOME --session-id "SESSION_ID" 2>/dev/null || true
|
|
```
|
|
|
|
If `PROACTIVE` is `false` or `off`: do not proactively invoke or suggest other gstack
|
|
skills during this session, including by asking whether to run one ("want me to run /X?").
|
|
Only run skills the user explicitly invokes. This preference persists across sessions via
|
|
`gstack-config`.
|
|
|
|
If `PROACTIVE` is `core` (default): **invoke the Skill tool** only for the four core
|
|
skills when the user's request matches their rule below: `/office-hours`, `/review`,
|
|
`/qa` and `/ship`. For every other rule, answer directly and do not suggest the skill;
|
|
the user types it. The browser step above and the **Failures** branches below follow the
|
|
same rule: under `core`, name `/browse` or `/investigate` for the user to type instead of
|
|
invoking it. A skill the user names is always invoked, whatever this setting says,
|
|
and a step inside a skill that is already running (a handoff, a review gate, a subagent it
|
|
dispatches) is part of that skill, not a suggestion.
|
|
|
|
If `PROACTIVE` is `all` (or `true`): **invoke the Skill tool** when the user's request
|
|
matches any skill's purpose. Do NOT answer directly when a skill exists for the task.
|
|
Use the Skill tool to invoke it. The skill has specialized workflows, checklists, and
|
|
quality gates that produce better results than answering inline.
|
|
|
|
**Routing rules — when you see these patterns, INVOKE the skill via the Skill tool** (under
|
|
`core`, only the four core rules auto-invoke):
|
|
- User describes a new idea, asks "is this worth building", brainstorms, pitches a concept → invoke `/office-hours`
|
|
- User asks to spec something out, file an issue, write up a ticket, "turn this into a GitHub issue", "backlog item" → invoke `/spec`
|
|
- User asks about strategy, scope, ambition, "think bigger", "what should we build" → invoke `/plan-ceo-review`
|
|
- User asks to review architecture, lock in the plan, "does this design make sense" → invoke `/plan-eng-review`
|
|
- User asks about design system, brand, visual identity, "how should this look" → invoke `/design-consultation`
|
|
- User asks to review design of a plan → invoke `/plan-design-review`
|
|
- User asks about developer experience of a plan, API/CLI/SDK design → invoke `/plan-devex-review`
|
|
- User wants all reviews done automatically, "review everything" → invoke `/autoplan`
|
|
- User reports a bug, error, failing test or broken behavior, "why is this broken", "this doesn't work", "wtf", "something's wrong" → check the cause by **Failures** below, then fix it or invoke `/investigate`
|
|
- User asks to test the site, find bugs, QA, "does this work", "check the deploy" → invoke `/qa`
|
|
- User asks to just report bugs without fixing → invoke `/qa-only`
|
|
- User asks to review code, check the diff, pre-landing review, "look at my changes" → invoke `/review`
|
|
- User asks to find code worth sharing, shared-code extractions, or duplication worth consolidating → invoke `/deslop-shared-libs`
|
|
- User asks to audit, prune or find low-value tests in the existing suite → invoke `/test-audit`
|
|
- User asks about visual polish, design audit of a live site, "this looks off" → invoke `/design-review`
|
|
- User asks to audit the live developer experience, time-to-hello-world → invoke `/devex-review`
|
|
- User asks to ship, deploy, push, create a PR, "let's land this", "send it" → invoke `/ship`
|
|
- User asks to merge + deploy + verify as one flow → invoke `/land-and-deploy`
|
|
- User asks to configure deployment for the project → invoke `/setup-deploy`
|
|
- User asks to monitor prod after shipping, post-deploy checks → invoke `/canary`
|
|
- User asks to update docs after shipping → invoke `/document-release`
|
|
- User asks to write docs from scratch, generate documentation, "document this feature/module" → invoke `/document-generate`
|
|
- User asks for a weekly retro, what did we ship, "how'd we do" → invoke `/retro`
|
|
- User asks to run a crew of agents, coordinate lanes, build a merge train, call a slot, validate a READY block, write the crew digest, "set up a captain", "run the crew" → invoke `/captain`
|
|
{{OUTSIDE_VOICE_ROUTING}}
|
|
- User asks for safety mode, careful mode → invoke `/careful` or `/guard`
|
|
- User asks to restrict edits to a directory → invoke `/freeze` or `/unfreeze`
|
|
- User asks to upgrade gstack → invoke `/gstack-upgrade`
|
|
- User asks to save progress, checkpoint, "save my work" → invoke `/context-save`
|
|
- User asks to resume, restore, "where was I" → invoke `/context-restore`
|
|
- User asks about security, OWASP, vulnerabilities, "is this secure" → invoke `/cso`
|
|
- User asks to make a PDF, document, publication → invoke `/make-pdf`
|
|
- User asks to pull data off a web page, "grab the table from", "extract the prices" → invoke `/scrape`
|
|
- User asks to launch a real browser for QA, "open the browser" → invoke `/open-gstack-browser` (fallback browser; on Aside the tabs are already visible)
|
|
- User asks to import cookies for authenticated testing → invoke `/setup-browser-cookies` (fallback browser; Aside already has the sessions)
|
|
- User asks to share the browser with another agent, "pair OpenClaw/Codex with my browser" → invoke `/pair-agent` (fallback browser)
|
|
- User asks to codify or save the last `/scrape` as a reusable skill → invoke `/skillify` (fallback browser)
|
|
- User asks about page speed, web performance regression → invoke `/benchmark`; model or skill benchmarks → invoke `/benchmark-models`
|
|
- User asks to plan, preregister, price or pilot a paid eval → invoke `/eval-plan`
|
|
- User asks to run a suite, build or eval on Ubicloud → invoke `/ubicloud`
|
|
- User asks what gstack has learned, "show learnings" → invoke `/learn`
|
|
- User asks to tune question sensitivity, "stop asking me that" → invoke `/plan-tune`
|
|
- User asks for code quality dashboard, "health check" → invoke `/health`{{VOICE_TRIGGER_ROUTING}}
|
|
|
|
**Failures: check the cause, then route.** A failing test, error or stack trace shows where a failure surfaces, not its root cause.
|
|
|
|
- **Cause supplied** (the user names a specific cause and a narrow fix): make one read-only check of the evidence it rests on, such as the named file, test or log. If that confirms the cause, make the fix and run the focused test that covers it. If it does not, invoke `/investigate` before any further tracing or edit.
|
|
- **Cause unknown:** make one read-only triage pass over the supplied evidence and the directly implicated test and code. Do not reproduce, test hypotheses or search wider. If that pass establishes the root cause and a narrow fix, make the fix and run the focused test that covers it. If the cause, scope or intended behavior is still unclear, invoke `/investigate` before any broader diagnosis or edit.
|
|
|
|
**Route only to skills in your available-skills list.** A rule above whose skill is
|
|
not listed there is turned off on this install; skip it, never try to invoke it.
|
|
|
|
**When to invoke, and when not to.** Invoke when the request matches a skill's purpose:
|
|
the skill's workflow, checklists and gates beat an ad-hoc answer. Answer directly when
|
|
no skill matches, for a quick factual question or a small edit the user scoped
|
|
themselves, and when the user asks for a direct answer instead of a workflow.
|
|
|
|
If the user opts out of suggestions, run `gstack-config set proactive off`. If they want
|
|
every skill suggested, run `gstack-config set proactive all`. `gstack-config set proactive
|
|
core` restores the default (the four core skills only).
|