Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
[package]
name = "wally"
# Must equal [product] version in versions.toml (scripts/ci/check-versions.py).
version = "0.8.13"
version = "0.8.14"
edition = "2021"
rust-version = "1.93"
license = "Apache-2.0"
Expand Down
6 changes: 3 additions & 3 deletions Formula/wally.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@
class Wally < Formula
desc "Run models on your machine or your RunAnywhere account"
homepage "https://github.com/RunanywhereAI/wally"
version "0.8.13"
version "0.8.14"
license "MIT"

# macOS arm64 ships the Swift MLX host
# (llama.cpp + ONNX + Sherpa + MLX). Linux is not in this cut.
on_macos do
on_arm do
url "https://github.com/RunanywhereAI/wally/releases/download/v0.8.13/wally-0.8.13-macos-arm64.tar.gz"
# Placeholder -- the v0.8.13 release has not published a wally-named asset
url "https://github.com/RunanywhereAI/wally/releases/download/v0.8.14/wally-0.8.14-macos-arm64.tar.gz"
# Placeholder -- the v0.8.14 release has not published a wally-named asset
# yet. scripts/release/update-tap.sh re-stamps this from the real release
# checksum; a stale value here fails brew install's own hash check
# rather than installing something unverified.
Expand Down
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,23 @@ wally opencode

The default model is `glm-5.3-flash`. To change it, run `wally models default <model>`.

**Test an app you are authorised to test with an AI pentester:**

```bash
wally shannon -- -u https://staging.example.com -r ./my-repo
```

Needs Docker. Node 18+ is required unless Shannon 3.4.0 is installed on PATH. See [Shannon](docs/EDITORS.md#shannon).

**Scan repos you are authorised to test:**

```bash
wally deepsec -- init . ./my-repo
wally vvah -- scan --repo ./my-repo
```

DeepSec 2.3.10 needs Node 18+ for `npx` unless it is on PATH. VVAH 1.5.1 needs Python 3.11–3.14 (it installs with pip into a venv). Models come from your signed-in account or `WALLY_CLOUD_KEY`. See [Security tools](docs/EDITORS.md#security-tools).

**Get help:**

```bash
Expand Down
212 changes: 212 additions & 0 deletions docs/EDITORS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ tool starts the way you already have it configured, and wally wires nothing.
| `deepseek` | a `--patch` overlay on the argv that adds the provider to dsh's `llm-pi-ai` row; nothing enters `$DSH_HOME` |
| `prime-agent` | a temporary extension loaded with `-e` that registers the provider for the run, with the key in `RUNANYWHERE_API_KEY`; nothing enters `~/.prime/agent` |
| `command-code` | a `runanywhere-wally` provider merged into `~/.commandcode/providers.json` (it reads providers from nowhere else) and taken out when it exits: the original bytes go back if the file is unchanged, otherwise only that provider comes out. The file names `$WALLY_COMMAND_CODE_API_KEY` rather than holding the key. A local model, or a person with no Command Code sign-in, runs with `CMD_LOCAL_ONLY=1` (no Command Code gateway models, `/share`, `/usage` or server-side web tools); with no sign-in a placeholder `COMMAND_CODE_API_KEY` gets past Command Code's login screen. `--skip-onboarding --no-auto-update` are passed, `-t` is left to you. One run at a time (a lock in `~/.commandcode/`). Its own subcommands (`-- status`, `-- login`, …) run untouched; `-- acp` is wired, and there the editor picks the model |
| `shannon` | not a coding tool: it runs [Shannon](#shannon) on a model from your account. A `models.json` in your wally profile and `SHANNON_AI_MODEL` / `SHANNON_AI_API_KEY` / `SHANNON_AI_BASE_URL` in the child's environment only |
| `deepsec` | not a coding tool: it runs [DeepSec](#deepsec) on a hosted model from your account. Pi custom routing flags are injected for `init`, `setup`, `process` and `revalidate`; the API key is in `WALLY_DEEPSEC_API_KEY` for the child only |
| `vvah` | not a coding tool: it runs [VVAH](#vvah) on a hosted model from your account. A `config.local.yaml` names the model per role; `OPENAI_API_KEY` and `OPENAI_BASE_URL` are set for the child only |

Two flags go with `-m`. `--serve` holds the endpoint open and prints it instead
of launching anything, which is how a tool nobody has taught wally about gets
Expand Down Expand Up @@ -303,3 +306,212 @@ Any other OpenAI-compatible client sends the field itself, for example
`"reasoning_effort": "max"` beside `model` and `messages`, or
`extra_body={"reasoning_effort": "max"}` in the OpenAI Python SDK.

## Shannon

[Shannon](https://github.com/KeygraphHQ/shannon) is an open-source AI pentester
(AGPL-3.0, by Keygraph). It is a separate project that wally does not bundle.
`wally shannon` points it at the models on your account.

**Only scan systems you own or are explicitly authorised to test.** A scan
sends real attack traffic at the target URL.

What you need:

- Docker, running. Shannon starts its scan in containers.
- Node 18 or later, which brings `npx`. Skip this if you already have Shannon
`3.4.0` installed as `shannon` on your PATH.
- A signed-in account (`wally account login`), or a Cloud key from the console.
- Linux, macOS, or Windows through WSL2. Run wally inside WSL2 on Windows;
native Windows is refused.

```bash
wally account login
wally shannon -- -u https://staging.example.com -r ./my-repo
```

The arguments after `--` are Shannon's own, and with no Shannon command wally
runs `start`. Other commands pass through untouched:

```bash
wally shannon -- scans
wally shannon -- status my-scan
wally shannon -- logs my-scan
wally shannon -- stop my-scan
wally shannon -m glm-5.3-flash -- -u https://staging.example.com -r ./my-repo
```

`-m` picks the model; without it Shannon uses your default model
(`wally models default <model>`) if your account has it. A model your account
does not have is refused before anything starts.

For `start`, wally:

- runs the Shannon release it was checked against (`3.4.0`): your `shannon` on
PATH if it reports exactly that version, otherwise
`npx --yes @keygraph/shannon@3.4.0`;
- refreshes your sign-in first if it would end within four hours;
- writes every model your account can use, with its real context and output
limits, to `shannon/models.json` in your wally profile (owner-only, replaced
on every run) and passes it as `--models-config`;
- sets `SHANNON_AI_MODEL=runanywhere:<model>`, `SHANNON_AI_API_KEY` and
`SHANNON_AI_BASE_URL` (wally's endpoint) for Shannon's process only. The key
is never in the arguments or in `models.json`;
- removes `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `XAI_API_KEY` and
`WALLY_CLOUD_KEY` from Shannon's environment so none of them can take over
from your key. Your own shell is never changed.

`--models-config` is wally's to set, so passing your own with `start` is refused.

A signed-in session is short-lived. For a scan that runs longer than that,
create a Cloud key in the console and export it as `WALLY_CLOUD_KEY` before
running `wally shannon`; wally uses it instead of the session. It is read from
the environment only.

### Without wally

Shannon needs a Pi `models.json` describing the endpoint, and the model named
with the `runanywhere:` prefix chosen below. Write this as `models.json`:

```json
{
"providers": {
"runanywhere": {
"baseUrl": "https://inference.runanywhere.ai/v1",
"api": "openai-completions",
"authHeader": true,
"compat": { "supportsDeveloperRole": false },
"models": [
{ "id": "glm-5.3-flash", "input": ["text"] }
]
}
}
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
```

then:

```bash
unset OPENAI_API_KEY ANTHROPIC_API_KEY XAI_API_KEY # these take over from the key below
export SHANNON_USE_PI_AUTH=0 # do not reuse a local Pi login
export SHANNON_AI_API_KEY='YOUR_CLOUD_KEY'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: If a user already has provider keys or Pi auth enabled, this direct-use recipe inherits them; Shannon may use them instead of SHANNON_AI_API_KEY. Clear those overrides and set SHANNON_USE_PI_AUTH=0 before launching.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. When an issue isn't valid or won't be fixed in this PR, reply in its thread with the reason and then resolve the thread. At docs/EDITORS.md, line 394:

<comment>If a user already has provider keys or Pi auth enabled, this direct-use recipe inherits them; Shannon may use them instead of `SHANNON_AI_API_KEY`. Clear those overrides and set `SHANNON_USE_PI_AUTH=0` before launching.</comment>

<file context>
@@ -303,3 +306,200 @@ Any other OpenAI-compatible client sends the field itself, for example
+then:
+
+```bash
+export SHANNON_AI_API_KEY='YOUR_CLOUD_KEY'
+export SHANNON_AI_MODEL=runanywhere:glm-5.3-flash
+npx --yes @keygraph/shannon@3.4.0 start -u https://staging.example.com -r ./my-repo \
</file context>
Suggested change
export SHANNON_AI_API_KEY='YOUR_CLOUD_KEY'
unset OPENAI_API_KEY ANTHROPIC_API_KEY XAI_API_KEY WALLY_CLOUD_KEY
export SHANNON_USE_PI_AUTH=0
export SHANNON_AI_API_KEY='YOUR_CLOUD_KEY'

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed in b7c5c5d: the manual Shannon recipe now unsets OPENAI/ANTHROPIC/XAI keys and sets SHANNON_USE_PI_AUTH=0.

export SHANNON_AI_MODEL=runanywhere:glm-5.3-flash
npx --yes @keygraph/shannon@3.4.0 start -u https://staging.example.com -r ./my-repo \
--models-config ./models.json
```

For each model from `GET /v1/models`, map `max_input_tokens` to
`contextWindow`, `max_output_tokens` to `maxTokens`, and `input_modalities` to
`input` so Shannon knows the model's real limits and inputs. Do not use the
`openai:` prefix. Shannon's built-in `openai` provider speaks the Responses
API, which the endpoint does not serve; the `runanywhere` provider above speaks
chat completions. `GET /v1/models` lists the ids and limits available to your
account.

### Models that need approval

Some models need approval before an account can use them. If a model is not on
your account's list, wally says so. That can also mean a mistyped or nonexistent
id: check the id against `GET /v1/models` first, and request access in the
console only if the model is gated.

## Security tools

`wally deepsec` and `wally vvah` point open-source repo scanners at models on
your account. They are hosted-only: there is no local-model path. **Only scan
repos and systems you own or are explicitly authorised to test.**

Both need a signed-in account (`wally account login`), or a Cloud key from the
console. The key is never passed on the command line or written into config
files wally creates. For a run longer than a sign-in lasts, export a Cloud key
as `WALLY_CLOUD_KEY` before you start (for example
`export WALLY_CLOUD_KEY='YOUR_CLOUD_KEY'`); wally reads it from the environment
only and overrides competing variables for the child process only, never in
your shell.

## DeepSec

[DeepSec](https://www.npmjs.com/package/deepsec) is an npm CLI wally does not
bundle. Wally runs the release it was checked against (`2.3.10`): your `deepsec`
on PATH if it reports exactly that version, otherwise `npx --yes deepsec@2.3.10`
(same as Shannon). Bare `wally deepsec` is DeepSec `init` in
the current directory: run it from a repo you own, not from `$HOME`. DeepSec
still links a Vercel project (Sandbox identity) even when models go through
your RunAnywhere account.

What you need:

- Node 18 or later (`npx`). Skip this if `deepsec` `2.3.10` is on your PATH.
- A model on your account (`-m` or your default), from a signed-in account or
`WALLY_CLOUD_KEY`.

```bash
wally account login
wally deepsec -- init . ./my-repo
```

With no DeepSec command after `--`, wally runs `init`. Other subcommands pass
through unless they are `init`, `setup`, `process` or `revalidate`, which get
the hosted route:

```bash
wally deepsec -- status
wally deepsec -m glm-5.3-flash -- process
```

For those routed commands wally injects Pi-style flags ahead of yours:
`--agent pi`, `--model runanywhere/<id>` (Pi requires `provider/model`), `--model-auth custom`, `--ai-provider runanywhere`,
`--ai-base-url <console endpoint>`, `--ai-api-key-env WALLY_DEEPSEC_API_KEY`, and
`--ai-credential-header authorization:bearer`. It writes `models.json` under the
Wally profile and sets `PI_CODING_AGENT_DIR` plus `WALLY_DEEPSEC_API_KEY` for
DeepSec's process, and removes `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`,
`AI_GATEWAY_API_KEY` and `WALLY_CLOUD_KEY` from the child so nothing else can
override your key. Passing your own copy of any of those flags (`--agent`,
`--model`, `--model-auth`, `--ai-provider`, `--ai-base-url`, `--ai-api-key-env`,
`--ai-credential-header`) on those commands is refused; choose the model with
wally's `-m`.

## VVAH

[VVAH](https://github.com/visa/visa-vulnerability-agentic-harness) is a Python
CLI wally does not bundle. Wally runs the release it was checked against
(`1.5.1`). If `vvaharness` is missing, wally prints the install command, asks
``Install it now with `…`? [y/N]``, and on yes creates a venv under the Wally
profile (`<profile>/vvah/`) and pip-installs the `v1.5.1` tag.

What you need:

- Python 3.11–3.14 on PATH (`python3.12` is preferred; Homebrew's `python3` is
often 3.15, which VVAH cannot install on). Checked after you confirm install.
- A model on your account (`-m` or your default), from a signed-in account or
`WALLY_CLOUD_KEY`.

```bash
wally account login
wally vvah
```

With no VVAH command after `--`, wally runs `scan --repo . --remediate`. Run
that from a project directory, not `$HOME` (the profile config lives under
`~/.config/wally`, and VVAH refuses a `--config` inside the scan target). Other
commands pass through:

```bash
wally vvah -- scan --repo ./my-repo
wally vvah -m glm-5.3-flash -- scan --repo ./my-repo
```

Each run rewrites `<profile>/vvah/config.local.yaml` (owner-only, 0600 on macOS
and Linux; on Windows it inherits the folder's permissions). If the profile
directory is inside the scan target, wally stages the config in a folder under
the system temp directory instead. Every active scanner role maps to your chosen
model with `via: openai`; the file never contains the API key. The child gets
`OPENAI_API_KEY` and `OPENAI_BASE_URL`, and wally removes `ANTHROPIC_API_KEY`,
`ANTHROPIC_SDK_API_KEY`, `ANTHROPIC_AUTH_TOKEN` and `WALLY_CLOUD_KEY` from it. VVAH's S10 stage can edit files on disk as part of a
scan; run it only on trees you are allowed to change.

If you confirm install and no supported Python (3.11–3.14, found as
`python3.12`, `python3.11`, `python3.13`, `python3.14` or `python3`) is on PATH,
wally prints `python 3.11 is not installed on this machine, Please install it first, Thank You`
and exits. If `python3` is newer than 3.14 it prints
`VVAH needs Python 3.11–3.14 (python3 is 3.15). Install Python 3.12, then run this again.`
instead. The venv is left in place for the next run.
5 changes: 3 additions & 2 deletions scripts/test/golden-capture.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,9 @@
"""
import argparse, json, os, re, shutil, subprocess, sys, tempfile

PASSTHROUGH = {'opencode', 'claude-code', 'claude-desktop', 'hermes', 'openclaw', 'deepseek'}
SECTIONS = {'Commands', 'Chat', 'Models', 'Coding tools', 'Account', 'Wally'}
PASSTHROUGH = {'opencode', 'claude-code', 'claude-desktop', 'hermes', 'openclaw', 'deepseek',
'shannon', 'deepsec', 'vvah'}
SECTIONS = {'Commands', 'Chat', 'Models', 'Coding tools', 'Security tools', 'Account', 'Wally'}
# Leaf commands whose invalid invocations are safe to run (parse fails first).
SAFE_LEAVES = ['run', 'llm generate', 'llm stream', 'llm tool-call', 'serve',
'models list', 'models show', 'models pull', 'models rm', 'models default',
Expand Down
31 changes: 31 additions & 0 deletions skills/runanywhere/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,33 @@ Offer to explain a harness before running it. Someone who has just signed up
does not yet know what opencode is, and "would you like me to explain how the
opencode harness works?" is a better second message than a launched TUI.

## Shannon and other tools

`wally shannon -- -u "$APP_URL" -r "$REPO_PATH"` runs Shannon, an open-source AI
pentester, on a model from the person's account. Only suggest it for a system
they own or are authorised to test. It needs Docker running, plus Node 18+ unless Shannon 3.4.0 is
installed on PATH, and wally sets up the model config and key itself. For a scan longer than a
sign-in lasts, the person exports a console Cloud key as `WALLY_CLOUD_KEY`.
Setup details, and how to point any other OpenAI-compatible tool at the
endpoint by hand, are in `docs/EDITORS.md`.

Comment thread
coderabbitai[bot] marked this conversation as resolved.
## Security tools

`wally deepsec` and `wally vvah` run hosted security scanners on a model from the
person's account. Only suggest them for a repo or system they own or are
authorised to test. DeepSec (2.3.10) needs Node 18+ for `npx` unless a `deepsec` on PATH reports exactly 2.3.10; VVAH (1.5.1) needs
Python 3.11–3.14. Wally sets up routing per tool (command-line flags for DeepSec, a
config file in the Wally profile for VVAH); keys go in the child environment
only, never on the command line, and competing variables are removed for that
child only. For a
run longer than a sign-in lasts, they export a console Cloud key as
`WALLY_CLOUD_KEY`. Details are in `docs/EDITORS.md`.

```bash
wally deepsec -- init . "$REPO_PATH"
wally vvah -- scan --repo "$REPO_PATH"
```

## Running a model directly

```bash
Expand Down Expand Up @@ -103,6 +130,10 @@ harness; those surfaces refuse it and point back here.
## When something is wrong

- **"not signed in"** — `wally account login`.
- **"not available on this account" or "not on your account's model list"** —
that model may need approval. Check the model id first; if it is right and the
model is gated, request access in the console. Do not log in again.
- **DeepSec or VVAH prerequisites missing** — install Node 18+ (DeepSec) or Python 3.11–3.14 (VVAH); see `docs/EDITORS.md`.
- **"that key is not valid"** — the key was revoked or expired; `wally account login` again.
- **opencode not installed** — `npm i -g opencode-ai`.
- **a model is slow or unavailable** — `wally backends` shows which engines this
Expand Down
8 changes: 8 additions & 0 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,8 +134,13 @@ pub fn configure_app(app: &mut App) {
"deepseek",
"prime-agent",
"command-code",
"shannon",
],
},
Section {
group: "Security tools",
names: &["deepsec", "vvah"],
},
Section {
group: "Account",
names: &["account"],
Expand Down Expand Up @@ -178,6 +183,9 @@ fn is_passthrough_command(token: &str) -> bool {
"deepseek",
"prime-agent",
"command-code",
"shannon",
"deepsec",
"vvah",
];
NAMES.contains(&token)
}
Expand Down
11 changes: 11 additions & 0 deletions src/cli_formatter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1200,6 +1200,11 @@ mod tests {
"Open OpenCode with a local or cloud model",
"Coding tools",
),
leaf(
"shannon",
"Test your own apps with Shannon, an AI pentester",
"Coding tools",
),
leaf("hermes", "Open Hermes with a model", "Coding tools"),
leaf("openclaw", "Open OpenClaw with a model", "Coding tools"),
leaf(
Expand All @@ -1217,6 +1222,12 @@ mod tests {
"Open Command Code with a model",
"Coding tools",
),
leaf(
"deepsec",
"Scan your own repos with DeepSec",
"Security tools",
),
leaf("vvah", "Scan your own repos with VVAH", "Security tools"),
namespace(
"account",
"Account",
Expand Down
Loading
Loading