mirror of
https://github.com/garrytan/gstack.git
synced 2026-10-31 22:14:25 +01:00
v1.91.290.0 feat(harness): gstack registers its skills in whatever agent harness it is installed into (GSTA-135) (#3526)
* wip: gstack-harness registrar (GSTA-135) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * wip: harness registration in setup, uninstall, tests Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * wip: harness hosts experimental, troubleshooting codes, kit Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: agent harness registration (GSTA-135) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: harness hosts run in place from the checkout in --status Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * test: bun-free ledger reader Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: CHANGELOG for harness registration (Unreleased) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(harness): keep edits beside themselves, never follow symlinks, cut only gstack's own context block Review blockers on #3526: uninstall deleted the edit backups under the state root; unregister followed a symlinked folder below the destination; a lone or edited context marker made the cut eat user lines; a re-register adding --context left an unrecorded block. Also: ledger written before the files, --refresh-registered no longer re-runs harness hosts through setup (gstack-harness refresh keeps their mode), bash goes through runBashSync, and setup tests follow openclaw/hermes becoming installs. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix(harness): a ledger with no destination row touches nothing (no hang) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: harness registration in README, install and hosts (document-release audit) 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>
This commit is contained in:
1 parent
a14c28aca7
commit
44f19d0106
28 files changed
+1549
-129
No files matched your search
+23
-10
@@ -135,9 +135,11 @@ generator's exact `openai.yaml` shape, byte identity with the checkout) is
|
||||
moved to `$GSTACK_STATE_ROOT/backups/host-renders/<ts>-<id>/`; every other file
|
||||
stays where it is, and only directories left empty are removed. The backup's
|
||||
`prune.log` lists every path. A gstack-upgrade migration runs
|
||||
the same prune for an install upgraded without a setup run. Instruction-only
|
||||
hosts (Hermes, OpenClaw, GBrain) are never installed by setup, so a user who
|
||||
renders one by hand inside an install adds its name to the record first.
|
||||
the same prune for an install upgraded without a setup run. Harness hosts
|
||||
(OpenClaw, Hermes) render into a scratch directory and copy into the harness's
|
||||
own folder, so they never add a render to the checkout; GBrain is never
|
||||
installed by setup, so a user who renders it by hand inside an install adds its
|
||||
name to the record first.
|
||||
|
||||
## Host tiers and capabilities
|
||||
|
||||
@@ -149,7 +151,7 @@ rows, host errors, and the README host matrix, all checked against
|
||||
| Tier | Meaning |
|
||||
|---|---|
|
||||
| `full` | Installs, renders, passes the conformance kit, and has a dated certification record below. |
|
||||
| `experimental` | Installs and renders and passes the conformance kit; no certification record yet. |
|
||||
| `experimental` | Installs and renders and passes the conformance kit; no certification record yet. A harness host (`install.registration: 'harness'`: OpenClaw, Hermes) installs through `gstack-harness register` and is certified by `test/harness-register.test.ts` instead of the per-directory kit. |
|
||||
| `instruction-only` | No install arm. `./setup --host X` prints what to copy and changes nothing. |
|
||||
|
||||
Rendering alone never certifies `full`.
|
||||
@@ -275,13 +277,24 @@ root's extra markdown files (`ETHOS.md`, `review/*.md`) as skills, the
|
||||
partial-read behavior of `view_file` on long skills, `ask_question` option
|
||||
handling, and an upgrade from an existing install.
|
||||
|
||||
## Instruction-only hosts
|
||||
## Instruction-only hosts and agent harnesses
|
||||
|
||||
OpenClaw, Hermes, Slate and GBrain have no install arm. Hermes stays
|
||||
instruction-only until someone certifies a native install (#2826 measured one
|
||||
on Hermes 0.21.0): `./setup --host hermes` prints the digest path and the
|
||||
generator command, and the Hermes render writes `name: gstack-<skill>` so
|
||||
Hermes, which indexes skills by frontmatter name, cannot shadow them (#2825).
|
||||
Slate and GBrain have no install arm. OpenClaw and Hermes are harness hosts:
|
||||
`./setup --host openclaw|hermes` (and `./setup` run inside either) calls
|
||||
`bin/gstack-harness register`, which renders the host into a scratch
|
||||
directory and copies it into the harness's own skills folder with an ownership
|
||||
ledger (`lib/harness-register.ts`). The Hermes render writes `name:
|
||||
gstack-<skill>` so Hermes, which indexes skills by frontmatter name, cannot
|
||||
shadow them (#2825).
|
||||
|
||||
A harness that needs no render of its own (QM, dots, any other) is a row in
|
||||
`TARGETS` in `lib/harness-register.ts`, not a host file: give it a mechanism,
|
||||
a default destination, an inside-the-harness marker (an environment variable
|
||||
the harness sets for the commands its agent runs, never a guess), a presence
|
||||
check and, when it has one, the command that lists the skills it sees. Add its
|
||||
reason codes to `HARNESS_CODES` with a `docs/troubleshooting.md` section, a
|
||||
case to `test/harness-register.test.ts`, and a row to the table in
|
||||
[hosts.md](hosts.md#agent-harnesses).
|
||||
|
||||
## How it works
|
||||
|
||||
|
||||
+11
-3
@@ -180,8 +180,16 @@ The agent should:
|
||||
3. Add dispatch routing to AGENTS.md
|
||||
4. Verify with a test spawn
|
||||
|
||||
For gstack developers: `./setup --host openclaw` outputs this documentation.
|
||||
The actual artifacts are generated by `bun run gen:skill-docs --host openclaw`.
|
||||
**Native skills or ACP.** `./setup --host openclaw` (or `./setup` run inside an
|
||||
OpenClaw session) gives OpenClaw's own agent gstack's skills: one `gstack`
|
||||
router skill in `$OPENCLAW_STATE_DIR/skills`, rendered with OpenClaw's tool
|
||||
names and pointing at the installed gstack, so the agent runs gstack's
|
||||
workflows and helpers itself. Use ACP when the work should happen in a Claude
|
||||
Code session with the full install (hooks, Claude tool names); use native
|
||||
skills when the OpenClaw agent should do it. Both can be installed together.
|
||||
Install, verify and remove: [hosts.md](hosts.md#agent-harnesses).
|
||||
|
||||
The ACP artifacts in `openclaw/` are generated by `bun run gen:skill-docs --host openclaw`.
|
||||
|
||||
## What we don't do
|
||||
|
||||
@@ -190,4 +198,4 @@ The actual artifacts are generated by `bun run gen:skill-docs --host openclaw`.
|
||||
- No bidirectional learnings bridge (brain repo is the knowledge store)
|
||||
- No JSON schemas or protocol versioning
|
||||
- No SOUL.md from gstack (OpenClaw has its own)
|
||||
- No full skill porting (coding skills stay native to Claude Code)
|
||||
- No hand-ported coding skills (native registration copies the generated OpenClaw render)
|
||||
@@ -261,7 +261,9 @@ keeps the lease. `bin/gstack-lease list` shows `alive|dead|stale`, and
|
||||
up with the same hosts, model and browser flag (recorded in the git dir
|
||||
after a successful setup) and `gstack-doctor --check` passes; a warm rerun
|
||||
takes about a second. Each setup ends with its own `gstack ready (<host>)`;
|
||||
the installer then prints `gstack ready (claude, codex)`.
|
||||
the installer then prints `gstack ready (claude, codex)`. Both name a
|
||||
`--host`, so setup's agent-harness step ([hosts.md](hosts.md#agent-harnesses))
|
||||
never runs on a Capy machine.
|
||||
4. `gstack-doctor --check` for the requested workflow (`--for <skill>`,
|
||||
`--only <skill>`, or `--require <id,id>`; default `claude,codex,patch`),
|
||||
run with the launch PATH, so the trailer certifies the Bun workflows run.
|
||||
|
||||
+44
-2
@@ -1,11 +1,53 @@
|
||||
# Running gstack on other agents
|
||||
|
||||
The README has the host matrix: one row per agent with its tier, install
|
||||
command and first invocation. This page has the rest: OpenClaw, how a checkout
|
||||
command and first invocation. This page has the rest: agent harnesses (OpenClaw,
|
||||
Hermes, dots, QM, Muse Code, Grok and any other), how a checkout
|
||||
decides which agents it renders for, the per-host notes, outside-review
|
||||
providers, the Codex behavioral profile, model tiers, and the design binary's
|
||||
models.
|
||||
|
||||
## Agent harnesses
|
||||
|
||||
Installing gstack inside an agent harness registers its skills the harness's
|
||||
own way, in the same `./setup` run. `bin/gstack-harness` does the work and
|
||||
`lib/harness-register.ts` holds one target per harness.
|
||||
|
||||
**When it is automatic.** `./setup` with no `--host` (or `--host auto`)
|
||||
registers with the harness it runs inside: OpenClaw (its exec tool sets
|
||||
`OPENCLAW_SHELL=exec`), Hermes (`HERMES_AGENT=true`) or a Dot (`HOME=/home/dot`
|
||||
on a Dot's computer), or a harness found among setup's parent processes. It
|
||||
prints every path it wrote and the command that removes them. An explicit
|
||||
`--host claude` (or any other host) never writes under a harness folder, and
|
||||
neither does `./setup --local`.
|
||||
`./setup --no-harness-auto` or `GSTACK_HARNESS_AUTO=0` turns the automatic step off.
|
||||
|
||||
**What it writes.** Copies in the harness's own skills folder, never edits to
|
||||
`openclaw.json`, Hermes's `config.yaml` or any context file you did not name.
|
||||
Every file goes into a ledger, `$GSTACK_STATE_ROOT/harness/<id>.ledger`, with
|
||||
its sha256. Registering again changes only what changed; a folder or skill name
|
||||
gstack did not write stops it (`HARNESS_UNOWNED_ENTRY`); `gstack-uninstall`
|
||||
and `gstack-harness unregister` remove exactly the ledger's files, never
|
||||
through a symlink, and rename any file you edited to `<file>.edited-<time>`
|
||||
beside itself, where uninstall cannot take it. A context block is cut only
|
||||
when it is the one gstack wrote; an edited block is left for you. `./setup
|
||||
--refresh-registered` (what `/gstack-upgrade` runs) refreshes every registration.
|
||||
`gstack-harness status` lists them and runs the harness's own skill list where
|
||||
it has one (`visible to harness: yes`). Errors: [troubleshooting](troubleshooting.md#agent-harnesses-gstack-harness).
|
||||
|
||||
| Harness | What gstack registers | Install | Verify | Remove |
|
||||
|---|---|---|---|---|
|
||||
| OpenClaw | one `gstack` router skill (one description line in every request; its body lists every skill and its path) in `${OPENCLAW_STATE_DIR:-~/.openclaw}/skills/gstack`; `--skills all` registers every skill as its own top-level folder | `./setup --host openclaw`, or `./setup` inside OpenClaw | `openclaw skills list --json` shows `gstack` (source `openclaw-managed`, eligible) | `gstack-harness unregister openclaw` |
|
||||
| Hermes | every skill, as `gstack-<skill>` in one `gstack` category, in `${HERMES_HOME:-~/.hermes}/skills/gstack` (Hermes opens only skills it has indexed) | `./setup --host hermes`, or `./setup` inside Hermes | `hermes skills list` shows the `gstack-*` skills in category `gstack` | `gstack-harness unregister hermes` |
|
||||
| dots (feder-cr) | the `gstack` router in `/home/dot/skills/gstack`, which the Dot lists every turn | `./setup` on the Dot's computer, or `gstack-harness register dots` | the Dot's Skills page, or `GET /skills` | `gstack-harness unregister dots` |
|
||||
| QM | an org skill pack: `github.com/garrytan/gstack` at the installed commit, every skill imported (instruction-only there: discovery, no gstack runtime) | an org admin, with `GSTACK_QM_URL` and `GSTACK_QM_ADMIN_TOKEN` set: `gstack-harness register qm --yes` | QM's skill list for the org | `gstack-harness unregister qm --remote` archives the pack; without `--remote` only the local record goes |
|
||||
| Muse Code, Grok Build | nothing: both read `~/.claude/skills`, so the Claude install (`./setup`) is what they see, with Claude tool names | `./setup` | `gstack-harness status` runs `muse skills list` / `grok inspect` and reports *discovered (Claude-rendered, unverified)* | `gstack-uninstall` |
|
||||
| Grok Bot, any chat-only skill library | nothing on disk | `gstack-harness register generic --print`, then paste the router and block into the app | ask it for a gstack skill | delete the pasted text |
|
||||
| any other harness | the router in an Agent Skills folder you name, and/or a 600-byte routing block between `<!-- gstack:begin harness-routing -->` markers in a context file you name | `gstack-harness register generic --skills-dir <dir>` and/or `--context <file>`; `gstack-harness manifest generic` prints every skill as JSON | the harness's own skill list | `gstack-harness unregister generic` |
|
||||
|
||||
OpenClaw's ACP route below is unchanged: native registration gives OpenClaw's
|
||||
own agent gstack's skills; ACP spawns Claude Code with the full install.
|
||||
|
||||
## OpenClaw
|
||||
|
||||
OpenClaw spawns Claude Code sessions via ACP, so every gstack skill just works
|
||||
@@ -79,7 +121,7 @@ Outside reviews require the selected CLI to be installed and authenticated: Clau
|
||||
|
||||
## Instruction-only agents
|
||||
|
||||
**Instruction-only tier (any rules-reading agent — Zed, Amp, Jules, side projects):**
|
||||
**Instruction-only tier (any rules-reading agent that loads no skills — Zed, Amp, Jules, side projects):**
|
||||
copy the 2KB digest at [`agents-digest/gstack-AGENTS.md`](../agents-digest/gstack-AGENTS.md)
|
||||
into a location your agent reads (for example, append it to your project's `AGENTS.md`).
|
||||
It carries gstack's ethos, reuse ladder, and voice rules — no install required. The
|
||||
|
||||
+9
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
The README covers the two-step install. This page holds the details: what
|
||||
setup needs and how long it takes, the team-mode hook, the hooks setup
|
||||
registers in Claude Code, and how to remove gstack.
|
||||
registers in Claude Code, agent harness registration, and how to remove gstack.
|
||||
|
||||
## How long setup takes
|
||||
|
||||
@@ -47,6 +47,14 @@ prune-stale --repoint` removes dead gstack hook entries, re-points stale ones
|
||||
at the stable install, and collapses duplicates, printing one line (and
|
||||
writing a backup beside the file) only when it changed something.
|
||||
|
||||
## Agent harnesses
|
||||
|
||||
Run inside OpenClaw, Hermes or a Dot, `./setup` also registers gstack's skills
|
||||
with that harness, in the harness's own skills folder, and prints every path
|
||||
it wrote. It never does this when `--host` names another host or with
|
||||
`--local`. Turn it off with `./setup --no-harness-auto` or
|
||||
`GSTACK_HARNESS_AUTO=0`. Per-harness details, QM and any other harness: [hosts.md](hosts.md#agent-harnesses).
|
||||
|
||||
## Uninstall
|
||||
|
||||
See [uninstall.md](uninstall.md).
|
||||
@@ -5053,3 +5053,61 @@ a registered, unlocked worktree whose directory is already gone (`git worktree
|
||||
prune`); a locked one, or a `broken` row whose `.git` link is missing, reads
|
||||
`review` instead. `clean,ignored:<n>` means the tree is clean but holds
|
||||
gitignored entries (`.env`, build output) that go with the worktree.
|
||||
|
||||
|
||||
## Agent harnesses (gstack-harness)
|
||||
|
||||
`bin/gstack-harness` registers gstack's skills with the agent harness gstack is installed into (OpenClaw, Hermes, a Dot, QM, any other) and records every file it writes in `$GSTACK_STATE_ROOT/harness/<id>.ledger`. Each error line ends with its code and a link here. Per-harness install, verify and uninstall steps: [docs/hosts.md](hosts.md#agent-harnesses).
|
||||
|
||||
<a id="harness-unknown-target"></a>
|
||||
### `gstack-harness: unknown harness "<name>"` (HARNESS_UNKNOWN_TARGET)
|
||||
|
||||
The name is not one of openclaw, hermes, dots, generic, qm, muse or grok. For a harness gstack does not know, use `generic` with `--skills-dir` or `--context`, or `--print` to get the router and block to paste in.
|
||||
|
||||
<a id="harness-no-destination"></a>
|
||||
### `gstack-harness: <harness> has no default skills folder` (HARNESS_NO_DESTINATION)
|
||||
|
||||
`generic` has no default location, and gstack never guesses at your context files. Pass `--skills-dir <dir>` (an Agent Skills folder the harness reads) or `--context <file>` (a file it loads every session), or `--print` to write nothing.
|
||||
|
||||
<a id="harness-mode-unsupported"></a>
|
||||
### `gstack-harness: Hermes does not support --skills router` (HARNESS_MODE_UNSUPPORTED)
|
||||
|
||||
Hermes opens only skills it has indexed, so a router that points at unlisted files would not load. Drop `--skills` to take the harness's default (Hermes: all; OpenClaw, dots and generic: router).
|
||||
|
||||
<a id="harness-unsafe-destination"></a>
|
||||
### `gstack-harness: refusing to write into <dir>: <why>` (HARNESS_UNSAFE_DESTINATION)
|
||||
|
||||
The destination is your home folder, the filesystem root, inside the gstack checkout, a symlink (or holds one where gstack's own folders were), or a path with a tab or newline. Nothing was written. Pick the harness's own skills folder, for example `--skills-dir ~/.openclaw/skills`.
|
||||
|
||||
<a id="harness-unowned-entry"></a>
|
||||
### `gstack-harness: <path> already exists and gstack did not write it` / `a skill named <name> already exists at <path>` (HARNESS_UNOWNED_ENTRY)
|
||||
|
||||
gstack only replaces files its ledger says it wrote. A folder or a skill with the same name is yours (or another tool's), and harnesses resolve skills by name, so gstack stops instead of shadowing it. Rename or move that entry, then register again.
|
||||
|
||||
The same code stops `register generic --context <file>` when the file holds a `<!-- gstack:begin harness-routing -->` or `<!-- gstack:end harness-routing -->` line without exactly one partner, or a gstack block someone edited. Delete those marker lines (and the lines between them, once you have kept what you want), then register again.
|
||||
|
||||
<a id="harness-render-failed"></a>
|
||||
### `gstack-harness: could not render <harness> skills: ...` (HARNESS_RENDER_FAILED)
|
||||
|
||||
The harness's skills are rendered from this checkout with `scripts/gen-skill-docs.ts`. Run `bun install` in the checkout and register again; the last lines of the generator's output are in the message.
|
||||
|
||||
<a id="harness-budget-exceeded"></a>
|
||||
### `gstack-harness: router description is <n> bytes` / `context block is <n> bytes` (HARNESS_BUDGET_EXCEEDED)
|
||||
|
||||
The router's description (at most 300 bytes) and the context block (at most 600 bytes) go into every session, so gstack refuses to grow them. This is a gstack bug: report it with the byte count.
|
||||
|
||||
<a id="harness-not-registered"></a>
|
||||
### `gstack-harness: no registration named "<name>"` (HARNESS_NOT_REGISTERED)
|
||||
|
||||
There is no ledger for that harness or id under `$GSTACK_STATE_ROOT/harness`. `gstack-harness status` lists every registration on this machine with its id.
|
||||
|
||||
<a id="harness-qm-credentials"></a>
|
||||
### `gstack-harness: no QM admin credential in the environment` / `... needs --yes` (HARNESS_QM_CREDENTIALS)
|
||||
|
||||
Registering gstack in QM publishes an org skill pack, so it needs an org admin's credential and an explicit `--yes`. Set `GSTACK_QM_URL` and `GSTACK_QM_ADMIN_TOKEN` (or `GSTACK_QM_SIGNING_SECRET` with `GSTACK_QM_ADMIN_ACTOR`) in the environment and run `gstack-harness register qm --yes`. gstack never prompts for, prints or stores the credential; the message shows the exact request instead.
|
||||
|
||||
<a id="harness-qm-api"></a>
|
||||
### `gstack-harness: <METHOD> /v1/admin/skill-packs... returned HTTP <code>` / `... failed: timed out after 60 s` (HARNESS_QM_API)
|
||||
|
||||
QM's admin API refused or did not answer. gstack lists packs before it creates one and retries once, so rerunning never makes a second pack. Check the URL is QM core and the credential is an org admin; `gstack-harness status` shows whether a pack id was recorded.
|
||||
|
||||
+3
-2
@@ -8,7 +8,7 @@ If gstack is installed on your machine:
|
||||
~/.claude/skills/gstack/bin/gstack-uninstall
|
||||
```
|
||||
|
||||
This handles skills, symlinks, global state (`~/.gstack/`), project-local state, browse daemons, and temp files. Use `--keep-state` to preserve config and analytics. Use `--force` to skip confirmation.
|
||||
This handles skills, symlinks, harness registrations (the files `gstack-harness` wrote into OpenClaw, Hermes, a Dot or another harness, from their ledgers), global state (`~/.gstack/`), project-local state, browse daemons, and temp files. Use `--keep-state` to preserve config and analytics. Use `--force` to skip confirmation.
|
||||
|
||||
## Option 2: Manual removal (no local repo)
|
||||
|
||||
@@ -49,7 +49,8 @@ rm -rf ~/.gstack
|
||||
rm -rf "${CODEX_HOME:-$HOME/.codex}/skills/gstack"* 2>/dev/null
|
||||
rm -rf ~/.factory/skills/gstack* 2>/dev/null
|
||||
rm -rf ~/.kiro/skills/gstack* 2>/dev/null
|
||||
rm -rf ~/.openclaw/skills/gstack* 2>/dev/null
|
||||
rm -rf "${OPENCLAW_STATE_DIR:-$HOME/.openclaw}/skills/gstack"* 2>/dev/null
|
||||
rm -rf "${HERMES_HOME:-$HOME/.hermes}/skills/gstack" 2>/dev/null
|
||||
rm -rf ~/.cursor/skills/gstack* 2>/dev/null
|
||||
rm -rf ~/.config/opencode/skills/gstack* 2>/dev/null
|
||||
rm -rf ~/.gemini/antigravity-cli/skills/gstack* 2>/dev/null
|
||||
|
||||
Reference in new issue
Block a user