Skip to content

Instantly share code, notes, and snippets.

@douglaz
Last active August 11, 2026 03:39
Show Gist options
  • Select an option

  • Save douglaz/49bad9ea69678bd9dded04b9d7c1c5fd to your computer and use it in GitHub Desktop.

Select an option

Save douglaz/49bad9ea69678bd9dded04b9d7c1c5fd to your computer and use it in GitHub Desktop.
Tau bug report: --prompt-stdin initial :skill is unknown although startup discovery publishes it

--prompt-stdin: initial :skill is unknown although startup discovery publishes it

Summary

An initial :skill command submitted with tau --prompt-stdin is rejected as unknown even though the same project-local skill is discovered and becomes available to the session during startup. The equivalent command works in the interactive UI after extension readiness.

The observed event order is consistent with an initialization-order defect in the --prompt-stdin path: the initial agent's skill context contains only built-in skills, while later session discovery events contain the requested filesystem skill. This report does not establish whether the correct fix is to defer initial agent-context construction, refresh that context, or synchronize initial-prompt preprocessing with session discovery another way.

Environment

tau: tau 0.1.0 (e341951, 2026-08-09 23:02)
commit: e34195176e2f658dd9d84cba7d7bb7ea4ba7f197
OS: NixOS 26.11pre1047536.e72e4f299401 (Zokor)
kernel: Linux 7.1.6
architecture: x86_64
shell: GNU bash 5.3.15(1)-release
observed working directory: /tmp/tau-skill-repro
HOME: /home/master
XDG_CONFIG_HOME: unset
TAU_* environment variables: none

The local checkout and its remote master both resolved to the commit above.

Tau loaded /home/master/.config/tau/harness.yaml. The primary reproduction below explicitly selects the built-in engineer role. The only local override to that role is:

agents:
  role_groups:
    engineer:
      roles:
        engineer:
          effort: high

There is no required_skills setting on this role and no extensions override in the user configuration. Filesystem skill discovery is supplied by Tau's default built-in core-shell extension; the session reported it ready. The failure happens during prompt preprocessing, before any provider request.

I also reproduced the failure with a custom driver role that declares required_skills: [drive], but the built-in-role reproduction proves that required_skills is not necessary.

Minimal reproduction

Create a project-local skill with no symlinks or external repositories:

repro_dir=$(mktemp -d)
mkdir -p "$repro_dir/.agents/skills/tau-repro-skill"
cat > "$repro_dir/.agents/skills/tau-repro-skill/SKILL.md" <<'SKILL'
---
name: tau-repro-skill
description: Minimal skill for reproducing Tau initial prompt discovery.
---

# tau-repro-skill

Reply with the skill name and first Markdown heading only.
SKILL
cd "$repro_dir"

printf '%s\n' ':skill tau-repro-skill Smoke test only.' \
  | tau --role engineer --ephemeral --prompt-stdin

Observed result:

session_id: tau-skill-repro-nk8s5r
role: engineer
error: initial prompt failed (preprocessing): :skill: unknown skill `tau-repro-skill`

The failure was repeatable. The earlier external-skill reproduction also still failed when the first stdin write was delayed by two seconds:

(sleep 2; printf '%s\n' ':skill drive Smoke test only.') \
  | tau --role engineer --ephemeral --prompt-stdin

That delay is only one attempted variation; it is not an exhaustive test of non-interactive startup mechanisms.

Expected behavior

The initial :skill command should wait for discovery initialization and load the project-local skill, matching docs/skills.md at this commit:

A new agent's initial :skill command waits for its discovery initialization to finalize before this expansion.

Durable event evidence

I repeated the minimal reproduction without --ephemeral. The session ID was:

tau-skill-repro-8cgb16

I retrieved and reduced the relevant events with this exact command:

jq -c '
  select(.recorded_at_micros >= 1786419380583528
      and .recorded_at_micros <= 1786419380595782)
  | select(.event_name == "agent.initialization_context_set"
      or .event_name == "agent.prompt_queued"
      or .event_name == "extension.session_discovery_snapshot_declared"
      or .event_name == "harness.session_skills_available"
      or .event_name == "harness.notice"
      or .event_name == "agent.prompt_failed")
  | if .event_name == "agent.initialization_context_set" then
      {recorded_at_micros, event_name,
       effective_skill_count: (.event.payload.effective_skills | length),
       matching_skill_names: [.event.payload.effective_skills[]
         | select(.name == "tau-repro-skill") | .name]}
    elif (.event_name == "extension.session_discovery_snapshot_declared"
       or .event_name == "harness.session_skills_available") then
      {recorded_at_micros, event_name,
       skill_count: (.event.payload.skills | length),
       matching_skills: [.event.payload.skills[]
         | select(.name == "tau-repro-skill")
         | {name, file_path, source, add_to_prompt,
            user_invocable, disable_model_invocation}]}
    else
      {recorded_at_micros, event_name, payload: .event.payload}
    end
' ~/.local/state/tau/sessions/tau-skill-repro-8cgb16/events.jsonl

Its verbatim output was:

{"recorded_at_micros":1786419380583528,"event_name":"agent.initialization_context_set","effective_skill_count":25,"matching_skill_names":[]}
{"recorded_at_micros":1786419380585471,"event_name":"agent.prompt_queued","payload":{"agent_id":"M9sEht","text":":skill tau-repro-skill Smoke test only.\n","message_class":"user"}}
{"recorded_at_micros":1786419380592301,"event_name":"extension.session_discovery_snapshot_declared","skill_count":41,"matching_skills":[{"name":"tau-repro-skill","file_path":"/tmp/tau-skill-repro/.agents/skills/tau-repro-skill/SKILL.md","source":null,"add_to_prompt":true,"user_invocable":true,"disable_model_invocation":false}]}
{"recorded_at_micros":1786419380592482,"event_name":"harness.session_skills_available","skill_count":66,"matching_skills":[{"name":"tau-repro-skill","file_path":null,"source":{"kind":"file","path":"/tmp/tau-skill-repro/.agents/skills/tau-repro-skill/SKILL.md"},"add_to_prompt":true,"user_invocable":true,"disable_model_invocation":false}]}
{"recorded_at_micros":1786419380592733,"event_name":"harness.session_skills_available","skill_count":66,"matching_skills":[{"name":"tau-repro-skill","file_path":null,"source":{"kind":"file","path":"/tmp/tau-skill-repro/.agents/skills/tau-repro-skill/SKILL.md"},"add_to_prompt":true,"user_invocable":true,"disable_model_invocation":false}]}
{"recorded_at_micros":1786419380595763,"event_name":"harness.notice","payload":{"kind":"harness.notice","message":":skill: unknown skill `tau-repro-skill`","level":"info"}}
{"recorded_at_micros":1786419380595782,"event_name":"agent.prompt_failed","payload":{"request_id":"ui-create-764044-1","agent_id":"M9sEht","ctx_id":"ui-prompt-764044-2","stage":"preprocessing","message":":skill: unknown skill `tau-repro-skill`"}}

No discovery diagnostic was emitted for the project skill. A second discovery snapshot containing the same valid candidate followed the failure; it is omitted above as redundant.

These events establish that the initial agent context did not contain the project skill, while filesystem discovery subsequently found it and the session published it as available. The availability event was recorded before the preprocessing failure event, but the trace does not expose the precise instant at which preprocessing performed its skill lookup. The evidence therefore narrows the defect to startup synchronization between session discovery, initial agent skill context, and initial-prompt preprocessing without proving the exact internal mechanism.

Interactive control

Using the same minimal project, role, configuration, working directory, and environment, I started:

tau --role engineer --ephemeral

I waited until Tau displayed ready for all five started extensions: core-shell, provider-builtin, std-notifications, std-utils, and std-websearch. I then submitted:

:skill tau-repro-skill Smoke test only.

Before connecting to the provider, Tau directly rendered the preprocessed prompt expansion:

initialized zR3yPT
skills:
  tau-repro-skill 1L, 59B
  tau-self-knowledge 1L, 235B
  64 other session skills available

<skill name="tau-repro-skill" location="/tmp/tau-skill-repro/.agents/skills/tau-repro-skill/SKILL.md">
References are relative to /tmp/tau-skill-repro/.agents/skills/tau-repro-skill.

# tau-repro-skill

Reply with the skill name and first Markdown heading only.
</skill>

Smoke test only.
Connecting to provider…

The model subsequently returned tau-repro-skill and # tau-repro-skill, but the harness-rendered expansion above is the direct control evidence. This shows that discovery and user invocation work after interactive startup. It narrows the failure to initial non-interactive startup without identifying its precise internal cause.

Possible boundary to inspect

One hypothesis is that --prompt-stdin constructs the initial agent's skill context before the default discovery extension has published its session snapshot, then preprocesses the initial prompt against that earlier context. Relevant boundaries include completion of extension discovery, construction or updating of the initial agent context, and the point at which initial-prompt preprocessing is released.

The interactive control proves successful invocation after readiness, but does not by itself prove that the interactive path constructs the agent at a different startup point.

Workaround

The confirmed workaround is to use interactive Tau, wait for extension readiness, and then submit the first skill invocation.

I did not find a non-interactive workaround in the cases tested. In particular, delaying the first stdin write by two seconds did not change the external-skill reproduction. I have not exhaustively tested other non-interactive startup or preloading mechanisms.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment