You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Browse filesBrowse the repository at this point in the historyBrowse files
Ovtcharov
committed
feat(skills): let the agent install and sign in to a skill's CLI
Asking GAIA to triage GitHub issues on a machine without the GitHub CLI ended
the conversation: the agent said "install gh and run gh auth login", and the
user went and did it by hand. It can now do both itself, after asking.
Three tools on the flagship agent, driven by data on the binary policy rather
than by new branches:
- check_cli_setup reports one of five states, each with a different remedy.
Splitting them matters most for env_token — gh authenticated from $GH_TOKEN
works fine, and refuses to store a credential while that variable is set, so
reporting it as "logged out" sends the user to run a command gh will reject.
- install_cli runs the platform package manager. Linux is deliberately absent:
gh is not in stock Debian or Fedora repositories, and adding GitHub's apt/dnf
repo is a root-level trust change that belongs to the user.
- sign_in_cli drives the browser device flow, hands over the one-time code and
URL, and waits on the CLI's own exit rather than on a second approval prompt.
Watching the child observes GitHub completing the grant instead of the user
reporting that it did, and avoids stranding a polling process behind a
confirmation channel that either expires in a minute or blocks forever.
Both mutating tools show the exact command and cannot be pre-authorized: no
"always" grant is offered, and a loaded skill grant exempts only read-only
run_shell_command. The command argument is display-only and verified against
the policy table before anything runs, so the prompt cannot show one command
and execute another.
Also narrows the gh auth grant. `gh auth token` was already refused as a
credential surface, but `gh auth status --show-token` prints the same token and
ran at the tier that asks nobody; it is now denied on the flag, ahead of action
classification.
Scopes requested are repo and read:org — what the triage skill's command table
can reach, and nothing beyond it. The token and the one-time code are never
logged, returned, or persisted by GAIA.
Copy file name to clipboardExpand all lines: docs/guides/gaia.mdx
+37-4Lines changed: 37 additions & 4 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -85,7 +85,7 @@ It answers **200** when ready and **503** when not, with a `hint` naming the fix
85
85
86
86
## Tool surface
87
87
88
-
The default construction registers **67 tools** — the 55 of the Chat agent's `full` profile, plus 7 skill-library tools, 4 code-search tools, and the `load_tools` escape hatch. Grouped by what they're for:
88
+
The default construction registers **70 tools** — the 58 of the Chat agent's `full` profile, plus 7 skill-library tools, 4 code-search tools, and the `load_tools` escape hatch. Grouped by what they're for:
89
89
90
90
| Area | Tools |
91
91
|---|---|
@@ -96,22 +96,55 @@ The default construction registers **67 tools** — the 55 of the Chat agent's `
| Run control |`request_user_input`, `set_loop_state`, `load_tools`|
102
103
103
104
That count is what the agent *can* do, not what it sees at once: per-turn tool selection sends the model a subset of the registry on any one call, and `load_tools` is the escape hatch it calls mid-turn to pull in a bundle the selector missed. No capability is lost either way.
104
105
105
-
`run_shell_command` is restricted to a read-only command allowlist (`ls`, `cat`, `grep`, `find`, `stat`, `df`, `uname`, and similar) and rate-limited. Anything that writes, installs, or executes an arbitrary binary is refused.
106
+
`run_shell_command` is restricted to a read-only command allowlist (`ls`, `cat`, `grep`, `find`, `stat`, `df`, `uname`, and similar) and rate-limited. Anything that writes, installs, or executes an arbitrary binary is refused — a package manager is not on that allowlist and cannot be talked onto it. Installing the specific CLIs a skill needs goes through [its own tools](#setting-up-a-cli-a-skill-needs) instead.
106
107
107
108
**Image *generation* is deliberately off.** Drawing a picture would pull a second model into Lemonade and evict the resident chat model mid-conversation — not a trade a document agent should make silently. A custom agent can still compose the [`sd` tool mixin](/sdk/mixins/tool-mixins#95-stable-diffusion-mixin) when that trade-off is acceptable.
108
109
110
+
### Setting up a CLI a skill needs
111
+
112
+
Some skills run a command-line tool rather than calling an API — [`github-triage`](/guides/starter-skills#github-triage) needs the GitHub CLI, which owns its own login. When that tool is missing or logged out, the agent sets it up for you instead of handing you instructions and stopping.
113
+
114
+
Ask for it in plain words — *"set up the GitHub CLI"* — and three tools do the work:
115
+
116
+
| Tool | What it does |
117
+
|---|---|
118
+
|`check_cli_setup`| Reads the CLI's own status. Changes nothing and never prompts. |
119
+
|`install_cli`| Installs it with your package manager, after you approve the exact command. |
120
+
|`sign_in_cli`| Starts the browser sign-in, after you approve the exact command. |
121
+
122
+
The check reports one of five states, and only one of them means "sign in":
123
+
124
+
| State | What it means | What fixes it |
125
+
|---|---|---|
126
+
|`ready`| Installed, signed in, permissions present. | Nothing. |
127
+
|`missing`| Not on `PATH`. | Install it. |
128
+
|`unauthenticated`| Installed, no working credential. | Sign in. |
129
+
|`insufficient_scopes`| Signed in, but the token lacks a permission the skill needs. | Sign in again — the flow re-requests it. |
130
+
|`env_token`| Signed in from a `GH_TOKEN` / `GITHUB_TOKEN` environment variable. **This works.**| Nothing, unless you *want* a browser login — then clear the variable first, because `gh` refuses to store its own credential while it is set. |
131
+
132
+
**You approve every install and every sign-in, one at a time.** Both are in the confirmation set below, and neither offers an "always" — there is no way to pre-authorize them, and loading a skill does not exempt them.
133
+
134
+
**Signing in is a handoff, not automation.** GAIA starts `gh auth login --web`, shows you the one-time code and the device URL, and waits. You enter the code in your browser; the agent cannot type it for you. Afterwards it re-checks and confirms the permissions actually arrived, rather than trusting the exit code. GAIA requests exactly the scopes the skill's commands can reach — `repo` and `read:org` for GitHub — and never sees the token.
135
+
136
+
If any step can't finish — no code appears, the code expires, the browser sign-in fails — it says so and gives you the command to run by hand. It never reports a setup that didn't happen.
137
+
138
+
<Note>
139
+
**Linux has no automated install, on purpose.** The GitHub CLI is not in the stock Debian or Fedora repositories, and the real install adds GitHub's apt/dnf repository — a root-level trust decision that is yours, not an agent's. On Linux you get [cli.github.com](https://cli.github.com) instead. Windows uses `winget`, macOS uses `brew`.
140
+
</Note>
141
+
109
142
### Tools that need your approval
110
143
111
-
Six tools mutate your machine and are gated behind an explicit confirmation: **`write_file`**, **`edit_file`**, **`run_shell_command`**, **`execute_python_file`**, and — because installing a skill writes third-party code under `~/.gaia/skills` and removing one deletes it — **`install_skill`** and **`remove_skill`**. Everything else — reading, indexing, querying, web fetching, memory — runs without asking.
144
+
Eight tools mutate your machine and are gated behind an explicit confirmation: **`write_file`**, **`edit_file`**, **`run_shell_command`**, **`execute_python_file`**, **`install_cli`**and **`sign_in_cli`** (they install software and sign you in to an account), and — because installing a skill writes third-party code under `~/.gaia/skills` and removing one deletes it — **`install_skill`** and **`remove_skill`**. Everything else — reading, indexing, querying, web fetching, memory, and `check_cli_setup` — runs without asking.
112
145
113
146
<Warning>
114
-
**Over the sidecar's `/query` stream, all six are refused rather than prompted.** That
147
+
**Over the sidecar's `/query` stream, all eight are refused rather than prompted.** That
115
148
surface has no way to collect an approval, so instead of pretending to, the run stops
116
149
with a message saying which action it declined. If your workflow depends on the agent
117
150
writing files, drive it from a surface that can prompt you, or perform the write yourself.
|`cli_setup`|`from gaia.agents.tools.cli_setup_tools import CliSetupToolsMixin`| Install and sign in to a skill's CLI ([how it works](/guides/gaia#setting-up-a-cli-a-skill-needs)) |
Copy file name to clipboardExpand all lines: hub/skills/github-triage/SKILL.md
+27-15Lines changed: 27 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
name: github-triage
3
3
description: Triage GitHub work with the gh CLI — your unread notification inbox, or one repository's issue backlog. Groups what arrived, judges what is urgent, and posts the reply once you approve it. Use when asked to triage issues or notifications, check the GitHub inbox, see what needs attention or what you are blocking, review a backlog, comment on or label an issue, or work out what to fix first.
4
4
license: MIT
5
-
version: 2.1.0
5
+
version: 2.2.0
6
6
metadata:
7
7
gaia:
8
8
security_tier: community
@@ -25,21 +25,33 @@ Run every GitHub command through `run_shell_command`.
25
25
26
26
## Setup
27
27
28
-
Check before you conclude anything is missing. A command that failed is not
29
-
proof `gh` is absent:
28
+
Call `check_cli_setup("gh")` first. It is read-only, prompts nobody, and returns
29
+
the one thing worth acting on — a `state`. Never infer setup from a `gh` command
30
+
that failed, and never run `gh --version` to guess.
30
31
31
-
```bash
32
-
gh --version # installed? ("gh version", no dashes, is refused)
33
-
gh auth status # logged in? prints the account and its scopes
34
-
```
35
-
36
-
-`gh --version` fails → not installed. Offer to install it: `winget install
That is not a `gh` command, so the user approves it per-call — ask, then run it.
39
-
-`gh auth status` fails → installed but not logged in. `gh auth login` is
40
-
interactive and you cannot drive it; hand that one step to the user.
41
-
- Any **other** failure is a bug in the command you sent, not a missing `gh`.
42
-
Quote the error and fix the command. Never diagnose it as "not installed".
32
+
|`state`| Remedy |
33
+
|---|---|
34
+
|`ready`| None. Start the triage. |
35
+
|`missing`|`install_cli`. Linux has no automated install — give the user https://cli.github.com.|
36
+
|`unauthenticated`|`sign_in_cli`. |
37
+
|`insufficient_scopes`|`sign_in_cli` — signing in again re-requests `repo` and `read:org`. |
38
+
|`env_token`|**Not a sign-in.**`gh` already works on a `GH_TOKEN`/`GITHUB_TOKEN` from the environment, and refuses to store its own credential while that is set. Say so and move on. |
39
+
40
+
Pass `command` back exactly as `check_cli_setup` returned it — `install_command`
41
+
or `sign_in_command`. That string is what the user sees in the approval prompt,
42
+
and one that does not match is refused rather than run.
43
+
44
+
Both tools stop and ask, every time: the user sees the exact command and answers
45
+
before anything runs. There is no "always", and loading this skill pre-approves
46
+
neither. Signing in is a **handoff** — GAIA starts the flow and shows a one-time
47
+
code and a URL, then waits while the user enters the code in their browser. You
48
+
cannot type it for them.
49
+
50
+
Report a setup failure as a failure. Both tools name the manual command when they
51
+
give up; hand that to the user rather than claiming a step succeeded.
52
+
53
+
Any **other**`gh` failure is a bug in the command you sent, not a missing `gh`.
54
+
Quote the error and fix the command. Never diagnose it as "not installed".
0 commit comments