- name
- ask
- description
- Use when the user asks to query project memory, ask an oracle, use supported browser-backed reviewers, run Tau roundtable/single-handler workflows, run persona/deep-review workflows, generate image prompts, check OS/project health through composed skills, or run an ask DAG. This skill is the executable /ask runtime; do not replace it with an informal subagent, plain web search, or hand-written review.
- triggers
- ["$ask","/ask","ask oracle","deep review","parallel review","roundtable","persona review","CAE gap review","browser oracle","ask DAG","Tau DAG","compete","bakeoff","captcha security evaluation"]
- provides
- ["Executable ask runtime for memory-backed answers, oracle calls, reviews, supported browser-backed review, Tau single-handler and roundtable workflows, Tau compete/bakeoff workflows, persona workflows, image generation, ask/scillm-style DAG runs, and strict Tau DAG runs.\n","Evidence artifacts for each run: request, status, events, and mode-specific review outputs.\n"]
- composes
- ["memory","scillm","surf","captcha","subagent-runner","browser-oracle","create-report","tau","interview","best-practices-roundtable","best-practices-competition","agentic-evals"]
- complies
- ["best-practices-skills","best-practices-tau-dag"]
- taxonomy
- ["orchestration","retrieval","review","validation","browser","resilience"]
- allowed-tools
- ["Bash","Read","Write","Edit","MultiEdit","Glob","Grep","mcp__surf__*","mcp__browser_oracle__*"]
- disciplines
- ["agentic-orchestration","research-retrieval"]
# ask
## Stop First
If the user names `$ask`, `/ask`, an ask mode, oracle, deep review,
parallel review, roundtable, argue, CAE gap review, or ask DAG, read this whole
file before acting. Then use the real runtime entrypoint unless the user
explicitly asks for a fallback or the runtime is unavailable and that fallback
is reported.
Do not substitute `spawn_agent`, a plain model call, a plain web search, a
manual summary, or an invented review for `$ask`.
## Runtime Entrypoint
Run commands from this directory. Pi skill-command syntax such as
`/skill:ask webgpt What is 2 + 2?` is a first-class shortcut: the leading
browser handler (`webgpt`, `webclaude`, `webkimi`, `webgemini`, or `webgrok`)
routes to a Tau `single-call` browser-handler DAG with `--execute --json`. Inline
Pi skill references such as `$ask webgpt What is 2 + 2?` and the spaced natural
language spelling `$ask web gpt What is 2 + 2?` must be treated the same way
(`web gpt` normalizes to `webgpt`). This is only a compatibility shortcut for Pi
users; it must not use the removed direct WebGPT oracle path.
`./run.sh tau-dag "<request>"` maps to the Typer `tau-dag run` subcommand
internally. `./run.sh team-plan "<request>" --team <preset>` renders a
role-based multi-agent plan and frozen Tau DAG preview; execution requires
explicit `--execute --live` (see README "Team Orchestration").
```bash
cd skills/ask
./run.sh --help
./run.sh webgpt What is 2 + 2?
./run.sh webgpt --compile-only What is 2 + 2?
./run.sh ask --help
./run.sh tau-dag run --help
```
Every nontrivial run must preserve the runtime artifacts. The standard artifact
set is:
- `<ask_id>.request.json`
- `<ask_id>.status.json`
- `<ask_id>.events.jsonl`
- mode-specific outputs such as `review.md`, `review.json`, DAG manifests, or
browser evidence
Runtime artifacts default under `.ask_artifacts/runs/<ask_id>` or the provided
`--run-output-root`. For long, live, or generated runs prefer a storage-backed
root such as `/mnt/storage12tb/skills/ask/outputs/...`. Do not commit generated
ask artifacts.
## Three Kinds Of Target
`/ask` addresses three peer target types. They differ in transport, not in
standing:
| Target | Example | Transport owner |
| --- | --- | --- |
| **Herdr session** — a live agent in a pane | `memory`, `w11:p13` | `$monitor-herdr` via `herdr pane run` |
| **Model call** — API/model handler | `gpt-5.5-high`, `deepseek-ai/DeepSeek-V3.2-TEE` | `$tau` (SciLLM is internal to Tau) |
| **Web model** — browser-backed reviewer (chat tab, NOT the agentic model; see the `webclaude` warning below) | `webgpt`, `webclaude`, `webkimi` | `$surf` + `$browser-oracle` |
A project agent should not care which side is browser, model, or live session
beyond naming the target.
## Talk To Another Agent's Session (Herdr)
Agents working in different Herdr sessions reach each other by name. Three
verbs, no ids to look up first:
```bash
cd skills/ask
./run.sh herdr list # every session you can talk to
./run.sh herdr who memory # what does this name resolve to?
./run.sh herdr send memory "Please fix graph-memory-operator#105"
```
`NAME` is whatever you already know — a project directory (`memory`), a GitHub
repo (`graph-memory-operator`), or an exact pane id (`w11:p13`). The first two
disagree on this machine: `~/workspace/experiments/memory` *is*
`grahama1970/graph-memory-operator`. Both spellings resolve to the same panes,
so you never have to remember which name a project answers to.
**Ambiguity is refused, never guessed.** Names are not unique — `memory`
currently matches 5 live panes and `agent-skills` 44. `send` stops and prints
the candidates plus a ready-to-paste command:
```
'memory' matches 5 live panes:
w11:p13 [codex/idle] /home/graham/workspace/experiments/memory
w7E:pK [claude/idle] /home/graham/workspace/experiments/memory
w88:p1 [opencode/idle] /home/graham/workspace/experiments/memory
Pick one by pane id:
./run.sh herdr send w11:p13 "<message>"
```
When names collide, `send` runs `$interview` and asks which session, listing
**session, model, and directory** for every candidate — the three facts that
tell identical names apart. Answer the question and the message is delivered;
no second command needed.
Exit codes let a caller branch without parsing prose: `0` delivered, `2`
ambiguous, `1` nothing addressable matched. `--json` returns the candidates
instead of interviewing, so a machine caller drives its own disambiguation;
`--no-interview` fails closed on ambiguity.
Two panes are never chosen for you:
- **Dead panes.** No agent attached, or Herdr reports `blocked`/`unknown` —
that is monitor-herdr's rule, reused here, and it means a human or a wedged
agent owns the pane.
- **Busy panes.** An agent mid-task is excluded so a message cannot interrupt
running work by accident. Pass `--busy` when interrupting is the intent.
Delivery goes through `herdr pane run`, the same transport `$monitor-herdr`
uses. A success receipt proves the prompt was *submitted*, not that the other
agent understood or acted on it — treat it as delivery proof only.
**`submitted: true` is herdr reporting on itself.** During development it
returned exit 0 for a pane whose content never showed the message, so confirm
delivery independently with `herdr pane read <pane_id>` when it matters.
`scripts/herdr_e2e_probe.sh` does exactly that and is wired into the agentic
evals as `herdr-live-delivery-readback-e2e`.
**Bidirectional round-trip** is proven separately by
`scripts/herdr_roundtrip_probe.sh` (eval case
`herdr-bidirectional-roundtrip-e2e`): it sends a nonce challenge and waits for
the agent's *reply*, requiring two or more occurrences — one for the echoed
prompt, one for the answer. Counting is harness-agnostic; reply markers are not
(codex renders `›` for input and `•` for output, other harnesses differ).
Round-trip needs a harness that echoes and answers in the pane, so it is
expected to work with pi/codex/claude-style TUIs and to skip elsewhere.
**Some panes report `idle` but are dead.** A blank readback is not about which
agent is running — it is about whether anything is still drawing to the
terminal. A live `opencode` pane spawns a separate TUI child
(`~/.cache/opencode/tui/tui-*`) that renders the screen; the panes that read
back as 0 bytes have the `opencode` process alive with **no TUI child**, so the
screen is genuinely empty and nothing can receive input. Herdr reports both
states as `agent_status: idle`, so status alone cannot tell them apart.
The rule that follows: **a pane whose screen cannot be read is not proven
addressable.** Both probes check readability before sending, which is also what
prevents a message being stranded in a wedged session — the failure mode that
produced `submitted: true` with nothing delivered.
### Never interrupt a pane mid-task
`send` refuses a pane that is still working, and `agent_status` cannot decide
that: Herdr reports `idle` between the turns of an active task, and its pane
record exposes no idle-age field (only agent, status, cwd, and ids). On
2026-08-09 eight probe messages landed in a pane running a ticket-closure job
for exactly that reason.
The signal that works is the screen itself. `is_quiescent()` samples the pane
twice a few seconds apart and treats any change as work in flight — an agent
mid-task redraws, a settled one does not. An unreadable pane counts as busy,
never as free. Pass `--interrupt` when interrupting is the intent.
A composer heuristic was tried and removed: matching the last `>`/`›` line
reads a harness's transcript of the previously submitted prompt as if it were
live input, and flags greyed placeholder hints like `Implement {feature}` as
real text. Delivery is verified after the fact instead of predicted before it.
Two conditions the probes report honestly rather than as `/ask` failures: a
target that received the message but is **out of provider credits** (skip, not
fail), and a `pane run` that types text which the harness leaves **unsent in
the composer** — observed once on a Claude Code pane, where `submitted: true`
was reported for a message still sitting at the prompt.
## Project-Agent Quickstart
Start here when the user asks for a single model call, roundtable, competition,
or creator-reviewer loop. Use one of these shapes; do not invent a custom
orchestration path.
| User intent | Command shape |
| --- | --- |
| One handler answers | `./run.sh tau-dag "<task>" --repo <repo> --target <target> --immutable-goal "<goal>" --handler <handler-or-model> --execute --json` |
| Roundtable | `./run.sh tau-dag "<shared task>" --repo <repo> --target <target> --immutable-goal "<goal>" --dag-template roundtable --handler <a> --handler <b> --topology concurrent --execute --json` |
| Competition | `./run.sh compete "<isolated task>" --repo <repo> --target <target> --immutable-goal "<goal>" --handler <a> --handler <b> --criterion <criterion> --execute --json` |
| Creator then reviewer | `./run.sh tau-dag "<creator task then reviewer verdict>" --repo <repo> --target <target> --immutable-goal "<goal>" --dag-template creator-reviewer --handler <creator> --handler <reviewer> --topology sequential --execute --json` |
Handlers are peers even when their transports differ. Browser handlers
(`webgpt`, `webclaude`, `webkimi`, `webgemini`, `webgrok`) run through `$surf`
and `$browser-oracle`. API/model handlers such as `gpt-5.5-high`,
`gpt-5.5-xhigh`, or `chutes deepseek-ai/DeepSeek-V3.2-TEE` are routed by Tau.
Project agents should not care which side is browser or API beyond naming the
handler.
For executed roundtables and competitions with browser handlers, Ask defaults to
`--browser-tab-lifecycle auto`. Auto creates one Chrome window, creates one tab
per requested browser handler, binds temporary browser-oracle projects, runs
Tau, and closes only that Ask-created window. The project agent does not need to
pre-create tabs or pass `--handler-project` for normal web seats. Use
`--browser-tab-lifecycle fresh-keep` only when a human needs to inspect the tabs
after the run. Use `--browser-tab-lifecycle reuse-bound` only when the human
intentionally wants the same long-lived provider tabs to keep their conversation
context across the whole roundtable or competition; preflight every named tab
before submission and keep the same binding for every round.
Ask-created browser seat windows land on **Desktop 2** (wmctrl index 1). They
are reviewer windows Ask provisioned, not windows the human asked for, so they
belong on the reviewer desktop rather than on top of current work. Override with
`ASK_REVIEWER_DESKTOP=<index>`; set it empty to disable placement and leave
windows wherever Chrome puts them.
Placement is cosmetic and never fails a run. It reuses `browser-oracle
place-window` — the same logic `open-bind` uses — rather than reimplementing
it, because two details there are easy to get wrong: wmctrl output order is not
creation order (a last-sorts heuristic moved the wrong window), so the window is
identified by diffing a snapshot taken before creation; and `wmctrl` returning 0
does not mean the move stuck, because KDE can bounce a freshly-mapped window
back to the active desktop, so the move is verified by readback and retried.
Pass local evidence a browser seat must actually see with `--attach-file <path>`
(repeatable) on `tau-dag run` or `compete`. Ask forwards each file to Surf as
`--attach-file` for browser handlers and records `requested_attachment_paths`
plus `browser_attachment_paths` in the node receipt. A missing file or a handler
that cannot attach fails the lane closed rather than answering from prose.
Attachment delivery needs an extension build that handles
`AI_UPLOAD_FILE_TO_TAB`; older extensions reject the upload and the lane reports
`browser_submit_not_accepted` with that message.
### How old is this tab?
Stale reviewer tabs are the usual cause of a browser lane that used to work:
conversation state accumulates, rate-limit banners persist, and bindings drift.
Check age before blaming the transport.
```bash
cd skills/surf
./run.sh tab.age # every tab, oldest first
./run.sh tab.list --with-age # ages on a normal listing
```
Read `age_source`, not just the number. `observed` is accurate; `at_least`
(shown with a `>=` prefix) means the tab predates the ledger and its real age
is unknown — Chrome exposes no creation time, so age is observed and
remembered, never read from the browser. `$surf` owns the ledger and the
contract; see its **Tab Age** section.
For a lane that is failing, the useful sequence is age first, then
`lane-diagnostics.json`, then the provider receipt — an old tab explains more
failures than anything in the code path does.
Browser providers do not share one payload contract. Before building or
repairing a browser roundtable packet, apply this matrix:
| Handler | Preferred review payload | Attachment rule | Explicit gotcha |
| --- | --- | --- | --- |
| `webgpt` | Short prompt plus one readable bundle | One attachment only; zip is allowed when the task needs a bundle | Multiple attachments fail before submission. Do not infer file creation from prose; download and verify generated artifacts. |
| `webgemini` | Short prompt plus one readable Markdown/text bundle | Ask inlines Markdown/text bundles for current Gemini tabs; do not rely on upload unless Surf records attachment metadata | Current Gemini UI may expose `Upload & tools` without an `input[type=file]`; stale page text can look like a response if sentinel capture is not strict. |
| `webkimi` | Short prompt plus one plain readable Markdown/text bundle | Do not use zip; Ask passes the Markdown/text bundle through Surf `kimi.submit --attach-file` | Kimi's Lexical composer can corrupt large inline payloads; do not paste or inline full review bundles into the composer. |
| `webclaude` | Prompt plus readable files | Multiple attachments are supported | Claude can stage a prompt without submitting it; require submit-acceptance and sentinel proof, not only a prepared prompt file. |
| `webdeepseek` / `deepseek` | Inline text or short prompt only | Attachments and zip files are unsupported | If local evidence is required, route through another handler or summarize the evidence into the prompt within size limits. |
Do not automatically convert every evidence set into a zip. For one-attachment
providers, choose the provider-compatible single file: usually Markdown for
Kimi and README/code review packets, and inline Markdown/text for Gemini when
the current tab lacks a file input; zip only when the provider is known to
accept it and the task actually needs an archive.
Failure classification must use the Ask browser failure-code registry in
`scripts/tau_roundtable_worker.py`, not bespoke prose. A lane is usable only
when its node receipt has `ok: true`, a non-empty response, and provider-specific
sentinel/attachment proof in metadata. `.submitted.md`, prepared prompts,
scheduler `node_completed`, and an Ask/Tau process exit code are not provider
acceptance proof.
Provider recovery must also be provider-specific. Ask must never turn a failed
browser lane into a generic `surf read`, `surf text`, page-text scrape, or
cross-provider extractor. If a submitted WebGrok lane misses the sentinel, the
recovery packet must name `surf grok.extract`; WebGPT uses
`surf webgpt.extract`; Gemini uses `surf gemini.extract` where applicable.
Handlers without a provider-owned extractor must fail closed with a ticket
instruction instead of pretending a generic page read is equivalent.
Browser lanes queue on the shared Surf browser lock. Ask derives the wait from
handler count and topology; pass `--browser-lock-timeout <seconds>` on `tau-dag
run` or `compete` to widen it for a busy browser. The resolved value is recorded
as `lock_timeout_seconds` in `browser-tab-lifecycle.json` and reaches each
browser handler's dispatch command.
After execution, read the returned `run_dir` and inspect:
- `dag.json`
- `command-specs/<node>/tau-dispatch-command.json`
- `node-artifacts/handler-*/node-receipt.json`
- `node-artifacts/handler-*/response.md`
- `node-artifacts/handler-*/browser-recovery-packet.json` when present
- `node-artifacts/handler-*/handler-recovery-packet.json` when present
- `node-artifacts/join/node-receipt.json` for roundtable
- `node-artifacts/join/compete-scorecard.json` for competition
Treat `PASS` as model/reviewer evidence only. Local closure still requires the
project's deterministic proof command or artifact validation. Treat `DEGRADED`,
`NEEDS_ATTENTION`, and provider rate limits as lane-local states: keep usable
peer receipts, read the recovery packet, and rerun only the affected lane or
launch a new round when appropriate.
Before launching a costly live browser panel, Ask runs a standard read-only
provider availability probe automatically. It inspects existing provider tabs
for visible rate-limit or capacity banners and writes
`<run_dir>/browser-provider-availability.json`; it does not submit prompts. If
the report is `ERROR`, or `NEEDS_ATTENTION` without specific provider cooldown
metadata, Ask exits before creating fresh browser tabs or dispatching Tau, with
`blocked_reason: browser_provider_unavailable_preflight`, `failure_code`, and
`next_command` in the top-level execution receipt. If `NEEDS_ATTENTION` names
provider-limited lanes, Ask treats that as lane-local: it records
`limited_providers` and `cooldown_policy` in the availability artifact, writes
`<run_dir>/browser-provider-selection.json`, removes unavailable requested
providers, and selects the next best available browser provider when the
workflow still has enough participants. WebGPT cooldowns opt the WebGPT worker
into one bounded Surf retry after 300 seconds only when that WebGPT lane is
still intentionally run.
Project agents can also run the same probe manually before a planned panel:
```bash
./run.sh browser-availability \
--provider webgpt \
--provider webclaude \
--provider webkimi \
--provider webgemini \
--output /tmp/ask-provider-availability.json \
--json
```
If this probe returns `ERROR` with `recovery_kind:
surf_stale_socket_no_listener`, `/tmp/surf.sock` exists but no Surf native host
is listening. This is local browser transport failure, not WebGPT provider
throttling. Follow the reported `next_command`; if it repeats, collect
`browser-provider-availability.json`, `/tmp/surf-host.log`, the native host
manifest, and `ss -xlpn | grep /tmp/surf.sock`, then file a `$ticket` to
`$surf`. Do not launch a browser roundtable, retry provider lanes, or classify
the failure as provider cooldown until Surf `tab.list` works again.
If the report is `NEEDS_ATTENTION` with `cooldown_policy.status:
LANE_LOCAL_RETRY`, do not cancel healthy peers. Treat only the named providers
as cooling down, preserve the policy, and use the adjusted handler list from
`browser-provider-selection.json`. If Ask cannot keep enough participants after
filtering unavailable providers, it exits with
Auf GitHub ansehen