mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-08 01:38:10 +01:00
* docs(readme): cut the README to the first ten minutes; move everything else to docs/ pages verbatim (GSTA-99) Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes Restore the /setup-gbrain code block the README split left open: README.md kept the ```bash opener and docs/gbrain-quick-tour.md got only the closing fence, so both pages rendered their body as one code block. Drop the self-referential 'Full reference' link in docs/domain-skills.md and make the troubleshooting quick-answer link an in-page anchor. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: describe the proactive core-set default in why-gstack The moved 'Proactive skill suggestions' paragraph now documents the four-skill core set, gstack-config set proactive core|all|off and the docs/proactive.md page that #3432 (gsta-99-proactive-core) adds; the CHANGELOG names it as the one non-verbatim paragraph of the move. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * fix: pre-landing review fixes (round 2) Promote docs/uninstall.md's moved sections from ### to ## so the page outline matches the other pages the README split created; no inbound link targets those anchors. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: documentation audit fixes The README Docs table no longer claims docs/standalone-binaries.md covers every gstack-* CLI (it documents the standalone ones), and docs/ADDING_A_HOST.md step 6 points at the README host-matrix row and docs/hosts.md, where the per-host notes now live. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: disclose the update check fully and list every setup hook The README privacy summary now names both GitHub requests the update check makes and the version/OS report it adds with telemetry on, as the full text it replaced did. docs/install.md's hooks section lists the team-mode SessionStart hook and the AskUserQuestion PreToolUse/PostToolUse hooks beside the timeline Stop hook. * docs: name the update check's conditional compare-API request bin/gstack-update-check also GETs api.github.com's compare endpoint when the remote VERSION equals the local one but main has moved; the README privacy summary and docs/privacy.md now list it beside the ls-remote and VERSION fetch (documentation audit). * fix: pre-landing review fixes (merge resolution) docs/install.md:21 carried main's stable-channel sentence twice after the merge, the second copy with its backticked spans stripped; the paragraph again matches README.md:41 verbatim with the relative link. Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com> * docs: say outside reviews are on by default in the README privacy summary The one-paragraph summary dropped the default-on disclosure the full text kept; mirror docs/privacy.md's parenthetical so the top-level page says which path sends code off-machine without an opt-in. * v1.91.246.0 stamp 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>
135 lines
7.4 KiB
Markdown
135 lines
7.4 KiB
Markdown
# Domain Skills
|
|
|
|
> **Scope:** domain-skills are a feature of gstack's own browser engine (`$B`), the **fallback** that runs when the Aside browser is absent (Linux, Windows, a closed Aside app). Skills driving Aside record per-project learnings through `/learn` instead. See [BROWSER.md](../BROWSER.md).
|
|
|
|
Per-site notes the agent writes for itself. Compounds across sessions: once an
|
|
agent figures out something non-obvious about a website, it saves a skill, and
|
|
future sessions on that host get the note injected into their prompt context.
|
|
|
|
This is gstack's borrow from [browser-use/browser-harness](https://github.com/browser-use/browser-harness).
|
|
gstack copies the per-site-notes pattern, NOT the self-modifying-runtime
|
|
pattern. Skills are markdown text loaded into prompts; they are not executable
|
|
code.
|
|
|
|
## How agents use it
|
|
|
|
```bash
|
|
# Agent wrote down what it learned about a site after a successful task.
|
|
# The host is taken from the active tab automatically (no agent argument).
|
|
echo "# LinkedIn Apply Button
|
|
|
|
The Apply button on /jobs/view pages is inside an iframe with a class
|
|
matching 'jobs-apply-button-iframe'. Use \$B frame --url 'apply' first,
|
|
then snapshot." | $B domain-skill save
|
|
|
|
# See what's saved
|
|
$B domain-skill list
|
|
|
|
# Read the body of a specific host's skill
|
|
$B domain-skill show linkedin.com
|
|
|
|
# Edit interactively in $EDITOR
|
|
$B domain-skill edit linkedin.com
|
|
|
|
# Promote an active per-project skill to global (cross-project)
|
|
$B domain-skill promote-to-global linkedin.com
|
|
|
|
# Roll back a recent edit
|
|
$B domain-skill rollback linkedin.com
|
|
|
|
# Delete (tombstone — recoverable via rollback)
|
|
$B domain-skill rm linkedin.com
|
|
```
|
|
|
|
## State machine
|
|
|
|
```
|
|
┌──────────────┐ 3 successful uses ┌────────┐ promote-to-global ┌────────┐
|
|
│ quarantined │ ─────────────────────▶ │ active │ ──────────────────▶ │ global │
|
|
│ (per-project)│ (no classifier flags) │(project)│ (manual command) │ │
|
|
└──────────────┘ └────────┘ └────────┘
|
|
▲ │
|
|
│ classifier flag during use │ rollback (version log)
|
|
└───────────────────────────────────────┘
|
|
```
|
|
|
|
A new save lands as **quarantined** and does NOT auto-fire in prompts. After 3
|
|
uses on this host without the L4 ML classifier flagging the skill content, the
|
|
skill auto-promotes to **active** in the project. Active skills fire on every
|
|
new sidebar-agent session for that hostname.
|
|
|
|
To make a skill fire across projects (for example, "I want my LinkedIn skill
|
|
on every gstack project I work on"), explicitly run
|
|
`$B domain-skill promote-to-global <host>`. This is opt-in by design (Codex T4
|
|
outside-voice review): blanket cross-project compounding leaks context across
|
|
unrelated work.
|
|
|
|
## Storage
|
|
|
|
Skills live in two places:
|
|
|
|
- **Per-project**: `~/.gstack/projects/<slug>/learnings.jsonl` — same JSONL
|
|
file the `/learn` skill uses. Domain skills are `type:"domain"` rows.
|
|
- **Global**: `~/.gstack/global-domain-skills.jsonl` — only `state:"global"`
|
|
rows.
|
|
|
|
Both files are append-only JSONL. Tombstones for deletes; an idle compactor
|
|
rewrites files periodically. Tolerant parser drops partial trailing lines on
|
|
read so a crash mid-write doesn't poison subsequent reads.
|
|
|
|
## Security model
|
|
|
|
Skills are agent-authored content loaded into future prompt context. That makes
|
|
them a classic agent-to-agent prompt-injection vector. The plan explicitly
|
|
addresses this with multiple layers:
|
|
|
|
| Layer | What | Where |
|
|
|-------|------|-------|
|
|
| L1-L3 | Datamarking, hidden-element strip, ARIA regex, URL blocklist | `content-security.ts` (compiled binary) |
|
|
| L4 | TestSavantAI ONNX classifier | `security-classifier.ts` (sidebar-agent, non-compiled) |
|
|
| L4b | Claude Haiku transcript classifier | `security-classifier.ts` (sidebar-agent) |
|
|
| L5 | Canary token leak detection | `security.ts` |
|
|
|
|
L1-L3 checks run at **save time** (in the daemon). The L4 ML classifier runs at
|
|
**load time** (in sidebar-agent), so each session that loads a skill into its
|
|
prompt also re-validates the content. This catches issues that only manifest
|
|
after a classifier model update.
|
|
|
|
The save command derives the hostname from the **active tab's top-level
|
|
origin**, not from agent arguments. This closes a confused-deputy bug Codex
|
|
flagged: a malicious page redirect chain could otherwise trick the agent into
|
|
poisoning a different domain.
|
|
|
|
## Error reference
|
|
|
|
| Error | Cause | Action |
|
|
|-------|-------|--------|
|
|
| `Save blocked: classifier flagged content as potential injection` | L4 score ≥ 0.85 at save | Rewrite the skill removing instruction-like prose; retry. |
|
|
| `Save blocked: <L1-L3 message>` | URL blocklist match or ARIA injection at save | Review skill body for suspicious patterns. |
|
|
| `Save failed: empty body` | No content via stdin or `--from-file` | Pipe markdown into `$B domain-skill save`, or pass `--from-file <path>`. |
|
|
| `Cannot save domain-skill: no top-level URL on active tab` | Tab is `about:blank` or `chrome://...` | `$B goto <target-site>` first, then save. |
|
|
| `Cannot promote: skill is in state "quarantined"` | Skill hasn't auto-promoted yet | Use it in this project until 3 successful runs without classifier flags. |
|
|
| `Cannot rollback: <host> has fewer than 2 versions` | Only one version exists | Use `$B domain-skill rm` to delete instead. |
|
|
|
|
## Telemetry
|
|
|
|
When telemetry is enabled (default `community` mode unless turned off), the
|
|
following events are written to `~/.gstack/analytics/browse-telemetry.jsonl`:
|
|
|
|
- `domain_skill_saved {host, scope, state, bytes}`
|
|
- `domain_skill_save_blocked {host, reason}`
|
|
- `domain_skill_fired {host, source, version}`
|
|
- `domain_skill_state_changed {host, from_state, to_state}` (planned)
|
|
|
|
Hostname only — no body content, no agent text. Disable entirely with
|
|
`gstack-config set telemetry off` or `GSTACK_TELEMETRY_OFF=1`.
|
|
|
|
## In brief: domain skills and the raw CDP escape hatch
|
|
|
|
Two browser primitives in gstack's own engine (the fallback path when Aside isn't there) compound the agent over time:
|
|
|
|
- **`$B domain-skill save`** — agent saves a per-site note (e.g., "LinkedIn's Apply button lives in an iframe") that fires automatically next time it visits that hostname. Quarantined → active after 3 successful uses → optional cross-project promotion via `$B domain-skill promote-to-global`. Storage lives alongside `/learn`'s per-project learnings file.
|
|
- **`$B cdp <Domain.method>`** — raw Chrome DevTools Protocol escape hatch for the rare case curated commands miss. Deny-default: methods must be explicitly added to `browse/src/cdp-allowlist.ts` with a one-line justification. Two-tier mutex serializes browser-scoped CDP calls against per-tab work. Output for data-exfil methods is wrapped in the UNTRUSTED envelope.
|
|
|
|
> Want raw CDP with no rails, no allowlist, no daemon — just thin transport from agent to Chrome? [browser-use/browser-harness-js](https://github.com/browser-use/browser-harness-js) is a different philosophy (agent-authored helpers vs gstack's curated commands) and a good fit if you don't want gstack's security stack. The two can coexist: gstack's `$B cdp` and harness can both attach to the same Chrome via Playwright's `newCDPSession`.
|